Smallest number from an array - java

Here is my challenge:
Given a list of non negative integers, arrange them in such a manner that they form the smallest number possible.
The result is going to be very large, hence return the result in the form of a string.
If I consider input array as {20, 1, 5} then all permutations are as below:
2015, 2051, 1205, 1520, 5201, 5120 but as 1205 is smallest hence it should be the result.
Input array {20, 1, 5}
Result: 1205
Here is the method signature:
private String getSmallestNumber(Integer[] nums) {
}
What algorithm should I use?
Similar type of question asked on:
http://www.practice.geeksforgeeks.org/problem-page.php?pid=380

I completed my code but please suggest me better algorithm
private String getSmallestNumber(Integer[] nums) {
String[] arr = new String[nums.length];
for (int i = 0; i < nums.length; i++) {
arr[i] = String.valueOf(nums[i]);
}
Arrays.sort(arr, new Comparator<String>() {
#Override
public int compare(String a, String b) {
return (a + b).compareTo(b + a);
}
});
StringBuilder sb = new StringBuilder();
for (String s : arr) {
sb.append(s);
}
while (sb.charAt(0) == '0' && sb.length() > 1) {
sb.deleteCharAt(0);
}
return sb.toString();
}

The solution is to sort the array using a custom comparator that compares digit-by-digit. In other words, given two numbers, compare the most-significant-digit of the first number to most-significant-digit of the second number. Then compare the second digits, and so on, until you reach the end of one of the numbers, or the digits aren't equal. The number with the lower digit goes first in the answer.
For example 20 comes before 5 because 2 is less than 5. 1000 comes before 99 because 1 is less than 9. 123789 comes before 1239 because 7 is less than 9.
So the trick is to scale the smaller number by multiplying by 10 until both numbers have the same number of digits. For example, given a six-digit number and a four-digit number like
123789
1239
you need to multiply the four-digit number by 100 so both numbers have the same number of digits
123789
123900
Then a simple integer comparison tells you that 123789 comes before 1239. So the code for the comparator looks like this
int compare( int a, int b )
{
int special = b - a; // special case, e.g. 123 and 123000
if ( a <= b ) {
for ( int n = 1; n <= b; n *= 10 )
if ( n > a )
a *= 10;
} else {
for ( int n = 1; n <= a; n *= 10 )
if ( n > b )
b *= 10;
}
if ( a == b )
return special;
else
return a - b;
}
There is a special case where the two numbers end up being equal after scaling. For example, given the numbers 123000 and 123, the correct order is to put 123000 before 123, since that puts the three zeros in the array first, i.e. 123000123 is better than 123123000. Hence a special case is needed to choose the larger number first, if the numbers are equal after scaling. Hence, the need for the variable called special.

Related

saving many intgers into 1 integer

I am trying to save many natural numbers that are smaller than m into 1 natural number n.
I need a function to read i'th number from n.
In python I can do it like:
def read(n,m,i):#reads a number on index i from n.
return n//m**i%m
def save(numbers_to_save, m=None):#saves natural numbers, that are smaller than m to n.
if m is None:
m=max(numbers_to_save)+1
n=0
for i_number in range(len(numbers_to_save)):
n+=m**i_number*numbers_to_save[i_number]
return n
numbers_to_save=[12,54,3,7,23,8,9,3,72,3]
i_max=len(numbers_to_save)
m=max(numbers_to_save)+1
n=save(numbers_to_save,m)
del numbers_to_save
for i in range(i_max):
print(read(n,m,i),end=",")
But how to do it effectively in java reading n only byte per byte? n is bigger than maximum value of long, so I can not use long to save n.
To translate this code to Java, you would need to use BigInteger class.
It works similarly to Python's "infinite" size integers, but with two key differences:
It is immutable, which means every time you change it, the result is a new object you must store in place of the old one.
You can't use regular operators (+, -, *, +) on it directly, but instead you must use the instance methods such as add or pow.
Here is an example of how your read function will look in Java:
int read(BigInteger n, BigInteger m, int i) {
return n.divide(m.pow(i)).mod(m).intValue();
}
Note, that for simplicity, this code assumes that both i and m will be smaller than MAX_INT.
It is possible to make both of them BigInteger as well to allow them to be of any size.
A long can be used for that specific given numbers (since m**count < Long.MAX_VALUE).
import static java.lang.Math.*;
public static long save(int m, int... numbers) {
long result = 0;
long mult = 1;
for (var num : numbers) {
if (num <0 || num >= m) throw new IllegalArgumentException("invalid: " + num);
result = addExact(result, multiplyExact(mult, num));
mult = multiplyExact(mult, m);
}
return result;
}
public static int read(long compressed, int m, int i) {
return (int) (compressed / (long)pow(m, i) % m);
}
private static void test() {
int[] numbers = { 12, 54, 3, 7, 23, 8, 9, 3, 72, 3};
int m = Arrays.stream(numbers).max().orElseThrow() + 1;
long compressed = save(m, numbers);
for (var i = 0; i < numbers.length; i++) {
int val = read(compressed, m, i);
if (val == numbers[i])
System.out.println(val);
else
System.err.printf("%d != %d # %d%n", val, numbers[i], i);
}
}
I am a bit lazy, so I used the Math methods addExactly and multiplyExact that throw an Exception in case of overflow. Alternative: check if long can save that count of numbers given m at start of method and use
result += mult * num;
mult *= m;
instead in the loop.
Use BigInteger as posted in this answer), if more space is needed.
this code also works with int to compress less, smaller values

How to calculate the number of zeros in binary?

Hi I am making a method that can take an integer as a parameter and compute how many zeros its binary form has. So for example, if I have binaryZeros(44), its binary form is 101100. Therefore, binaryZeros(44) should return 3. However, I am making some errors and I cannot tell where it is coming from. I would appreciate it if someone can point out where I am making that error, or if my approach (logic) to this problem is good enough. Thank you!
My code is Below:
public static int binaryZeros(int n) {
int zeroCount = 0;
double m = n;
while (m >= 0.0) {
m = m / 2.0;
if (m == Math.floor(m)) {
zeroCount++;
} else {
m = Math.floor(m);
}
}
return zeroCount;
}
Below is a more concise way to solve this problem
public static int binaryZeros(int n) {
int zeroCount = 0;
// Run a while loop until n is greater than or equals to 1
while(n >= 1)
{
/* Use modulo operator to get the reminder of division by 2 (reminder will be 1 or 0 as you are dividing by 2).
Keep in mind that binary representation is an array of these reminders until the number is equal to 1.
And once the number is equal to 1 the reminder is 1, so you can exit the loop there.*/
if(n % 2 == 0)
{
zeroCount++;
}
n = n / 2;
}
return zeroCount;
}
Your approach is good, but I think there's a better way to do it. The Integer class has a static method that returns the binary of a number: Integer.toBinaryString(num) . This will return a String.
Then, you can just check if there are any 0 in that string with method that has a for loop and evaluating with an if:
public int getZeros(String binaryString){
int zeros = 0;
for(int i=0; i < binaryString.length; i++)
if(binaryString.charAt[i].equals('0')
zeros++;
return zeros;
}
I believe this would be a simpler option and it doesn't have any errors.
Once m == 0.0, it will never change, so your while loop will never stop.
If you start with a number m >= 0, it can never become negative no matter how many times you divide it by 2 or use Math.floor. The loop should stop when m reaches 0, so change the condition to while (m > 0.0).
Note that you could do the same thing with built-in standard library methods. For example, there is a method that returns the number of leading zeros in a number, and a method that returns the number of bits set to 1. Using both you can compute the number of zeros that are not leading zeros:
static int binaryZeros(int n) {
return Integer.SIZE - Integer.numberOfLeadingZeros(n) - Integer.bitCount(n);
}
Here is one way. It simply complements the integer reversing 1's and 0's and then counts the 1 bits. You should not be using floating point math when doing this.
~ complements the bits
&1 masks the low order bit. Is either 1 or 0
>>> shifts right 1 bit including sign bit.
System.out.println(binaryZeros(44) + " (" +Integer.toBinaryString(44) +")");
System.out.println(binaryZeros(-44) + " ("Integer.toBinaryString(-44)+")");
public static int binaryZeros(int v) {
int count = 0;
while (v != 0) {
// count 1 bits
// of ~v
count += (~v)&1;
v >>>=1;
}
return count;
}
Prints
3 (101100)
4 (11111111111111111111111111010100)
Just be simple, whe there's Integer.bitCount(n) method:
public static int binaryZeros(int n) {
long val = n & 0xFFFFFFFFL;
int totalBits = (int)(Math.log(val) / Math.log(2) + 1);
int setBits = Long.bitCount(val);
return totalBits - setBits;
}
public static int getZeros(int num) {
String str= Integer.toBinaryString(num);
int count=0;
for(int i=0; i<str.length(); i++) {
if(str.charAt(i)=='0') count++;
}
return count;
}
The method toBinaryString() returns a string representation of the integer argument as an unsigned integer in base 2. It accepts an argument in Int data-type and returns the corresponding binary string.
Then the for loop counts the number of zeros in the String and returns it.

How many N length strings can be made from the alphabet? Need an efficient algorithm

The question is how many strings of length N can be made from the alphabet.
The conditions are:
Letters can be repetitive in a string
Only letters that are adjacent in the alphabet to a letter can be placed next to each other in the string. for example if N = 4, the strings can be ABCD, ABAB, ABCB, WXYZ, XWXW and so on. They can't be ABCE, CDEG, AAAA as only adjacent letters in the alphabet can be placed next to each other.
I have the answers for N when :
If N = 3, answer is 98
If N = 4, answer is 192
If N = 8, answer is 2896
If N = 15, answer is 342840
If N = 30, answer is 9841989098
If N = 40, answer is 9329564680878
I need to find the answer when N = 50. The algorithm I have made fetches the answer correctly till 30 in 10secs. However, after 30, I think due to the recursive nature of my algorithm, it keeps running and I haven't got an answer.
Here is my java code:
class Alphabet {
public int n;
public long counter = 0;
public static void main(String[] args) {
Alphabet a = new Alphabet(15);
a.run();
}
public Alphabet(int n) {
this.n = n;
}
public void run() {
for (int i = 0; i < 13; i++) {
this.attach(i, 1);
}
System.out.println(this.counter * 2);
}
public boolean attach(int letter, int length) {
if (length == this.n) {
this.counter++;
return true;
}
if (letter == 0) {
this.attach(1, length + 1);
return true;
}
if (letter == 25) {
this.attach(24, length + 1);
return true;
}
this.attach(letter - 1, length + 1);
this.attach(letter + 1, length + 1);
return true;
}
}
Is there a more efficient way to get the answer?
For each letter, calculate the number of strings of length 1 that end in that letter. For all letters, this is 1.
If you know the number of n-letter strings that end in each letter, then it's easy to calculate the # of n+1 letter strings that end in each letter. Given your rules, this takes O(alphabet_size) time. Do this repeatedly until you get to n=N. Then just add up the counts for all the letters and you're done.
If x[i][j] is the number of strings with j letters starting with letter i (numbered from 0), then x[i][j] satisfies these recurrence relations:
x[i][1] = 1
x[0][j] = x[1][j-1]
x[25][j] = x[24][j-1]
x[i][j] = x[i-1][j-1] + x[i+1][j-1]
That gives you an dynamic-programming style method for solving the problem. (here in Python since it makes the algorithm clearer, but there's no fundamental difficulty in converting it to Java):
def strings(n):
x = [1] * 26
for _ in xrange(n-1):
x = [x[1]] + [x[i-1] + x[i+1] for i in xrange(1, 25)] + [x[24]]
return sum(x)
print strings(40)
That is an O(n) (arithmetic operations) solution. It's possible to solve it in O(log n) arithmetic operations by computing the n'th power of a 26x26 matrix.
Let A be the matrix a[i][j] for i,j=0..25 where a[i][j] = 1 if |i-j]=1 otherwise 0.
Then:
x[][j] = A * (x[][j-1])
(This is just the recurrence relation written in matrix form).
Then:
x[][n] = A^(n-1) (x[][1])
Since the matrix power can be computed in O(log n) arithmetic operations (by exponentiation by squaring), once can compute the final x[][n] vector in O(log n) time. This in practice doesn't help much since the numbers become large, but if you need to compute the result mod K for some K, then this is an excellent approach.

Changing numbers places in java

Can anyone please learn me how to change this number 5486 to 4568 ? I need to change two pairs of numbers places. Any ideas please?
My code :
public Number shiftRight(int n) {
int length = (getNumOfDigits()+MINUSONE);
length = (int) Math.pow(TEN, length);
for (int i=0; i<n; i++){
int m=num%TEN;
num=(m*length) + (num/TEN);
}
return new Number(num);
}
public int shiftRightDistance(Number other){
int max = getNumOfDigits();
for (int i=0;i<max;i++)
{
if(compareTo(shiftRight(i))==ZERO)
{
return i;
}
}
return MINUSONE;
}
public Number swapPairs() {
}
}
The simplest (and least confusing) thing might be to convert the number to a char array, swap pairs of characters, and then convert back to a number. You can use String.valueOf(int), String.toCharArray(), new String(char[]) and Integer.valueOf(String) to put that together.
Alternatively, you can build on the following method that swaps the digits of a non-negative number less than 100:
private int swapDigitsLessThan100(int n) {
return 10 * (n % 10) + n / 10;
}
The way to build on that would be to extract every pair of digits from the original number, working recursively. The following deals with numbers that are an even number of digits long:
public int swapDigits(int n) {
if (n == 0) {
return 0;
return 100 * swapDigits(n / 100) + swapDigitsLessThan100(n % 100);
}
With this code, if n is an odd number of digits, the result will be to use a leading 0 as an additional digit.

Generating a multiple list of combinations for a number in Java

The following is the problem I'm working on and my snippet of code.
Is there a better way to implement this? I have used basic control structures for this below.
Is it better to store the rows and columns in a map and searching through the map based on the key/value pairs?
There is a security keypad at the entrance of a building. It has 9 numbers 1 - 9 in a 3x3 matrix format.
1 2 3
4 5 6
7 8 9
The security has decided to allow one digit error for a person but that digit should be horizontal or vertical. Example: for 5 the user is allowed to enter 2, 4, 6, 8 or for 4 the user is allowed to enter 1, 5, 7. IF the security code to enter is 1478 and if the user enters 1178 he should be allowed.
The following is a snippet of code i was working on:
ArrayList<Integer> list = new ArrayList<Integer>();
int num = 9;
int[][] arr = {{1,2,3},{4,5,6},{7,8,9}};
for(int i =0;i< arr.length;i++){
for(int j = 0; j <arr.length;j++){
if(num == arr[i][j]){
row = i;
col = j;
break;
}
}
}
for(int j1 = 0; j1< 3 ; j1++){
if(arr[row][j1] != num){
list.add(arr[row][j1]);
}
}
for(int i1 = 0 ; i1 <3;i1++){
if(arr[i1][col] != num){
list.add(arr[i1][col]);
}
}
There are many ways to solve this, but I think it can be solved with HashMaps and HashSets more efficiently than doing several iterations.
If I were you, I would build the data model first using a hash map and a hash set. This is because hash map and hash set have fast lookup, (no iterations)
HashMap<Integer,HashSet<Integer>> values = new HashMap<Integer, HashSet<Integer>>();
//now put in the accepted values for one
HashSet<Integer> oneValues = new HashSet<Integer>();
oneValues.put(1);
oneValues.put(2);
oneValues.put(4);
values.put(1, oneValues);
//put in 2 values
......
Then when you parse your input, if you want to see if an inputed value is accepted for what the code is, just do something like
private boolean isAccepted(int input, int combinationValue)
{
// check to see if the inputed value in the accepted values set
return values.get(combinationValue).contains(input);
}
I would tend to want a function along the lines of isCloseTo(int a, int b) So, say, if I called isCloseTo(5, 5) it would return true. If I called isCloseTo(2, 5) it should return true, too. But if I called isCloseTo(1, 3) it would return false.
So I'd write tests like that:
assertTrue(isCloseTo(5, 5));
OK, that's really easy to get to pass:
public boolean isCloseTo(int a, int b) {return true;}
Then, maybe
assertFalse(isCloseTo(1, 3));
which fails with the above implementation, so I'd need to change it
public boolean isCloseTo(int a, int b) {return a == b;}
That's still an incomplete implementation, so we need another test
assertTrue(isCloseTo(1, 2));
Now we start to need some real substance. And I think I'll leave the rest as an exercise for the reader. Yes, I've left the tricky bits out, but this is a strategy (test-driven design) that leads you more directly to solutions than just trying to write the code. As long as you keep all the test passing, you make steady progress toward a complete solution. Good luck!
There are many different acceptable solutions here. I suppose it's easier to construct 10x10 matrix of integer to check for the errors (for example errorMatrix). First index then will mean original digit, second index - digit typed by user, and value of arr[i][j] is a number of errors for this digit pair. Initialize it that way:
errorMatrix[i][i] = 0 //no error
errorMatrix[i][j] = 1, where i and j are horizontally or vertically neighboring digits
errorMatrix[i][j] = 2, in other cases.
Then for every digit pair you will get number of errors in O(1). You stated that you will accept only one error, so the value of 2 for unmatched pairs will be enough and you can just sum up the error numbers and compare it to one.
So, how to construct this. Iterate through all of the digit pairs and find the value of error. You should better implement function CheckError that will calculate it for digit pair a and b
if a=b, then errorMatrix is 0;
The digits a and b are vertical
neighbors if abs(a-b) = 3. So, is
abs(a-b)==3 set errorMatrix[a][b] =
1;
The digits a and b are horizontal
neighbors if
a. (a-1)/3==(b-1)/3 - here we check that this digits are on the same line.
b. abs(a-b)==1 - here we check that digits are in the neighboring cells.
If (a) and (b) then error value is 1;
In other cases error value is 2.
It seems to me that this spec is right. However, you need to test it before using
So, if you then want to handle the changes of the keypad layout you just have to rewrite CheckError method.
Hope it helps.
Or this...
boolean matchDigit(int p, int d) {
return (p==d)
|| (p==d-3)
|| (p==d+3)
|| (d%3!=1 && p==d-1)
|| (d%3!=0 && p==d+1);
}
this assumes we've already assured that p and d are between 1 and 9.
For the specific keyboard in your question we can use a base 3 to solve this problem and to calculate the distances between digits/keys.
1 { 1 / 3, 1 % 3 } = {0, 1}
2 { 2 / 3, 2 % 3 } = {0, 2}
...
5 { 5 / 3, 5 % 3 } = {1, 2}
...
8 { 8 / 3, 8 % 3 } = {2, 2}
public boolean isValidCode(int code, int expexted) {
while(code > 0)
{
if (!isValidDigit(code % 10, expected % 10))
return false ;
code /= 10 ;
expected /= 10 ;
}
return (code == expected) ;
}
public boolean isValidDigit(int a, int b) {
int dx = (a - b) / 3 ;
int dy = (a - b) % 3 ;
return ((Math.abs(dx) + Math.abs(dy)) == 1)
}
A more generic and robust solution will be to create a Map where you can set what other keys you accept.
Sample: allowing A, Z, P, M, N for A: place a new entry 'A'="AZPMN" in the map, validation checkd if the character is the same or if the type character is in the exceptions string.
private Map acceptedChars = new HashMap() ;
public void loadAcceptedCharacters() {
acceptedChars.put('A', "AZPMN") ;
}
public boolean isValidKeyword(String word, String expected)
{
if (word == null || word.matches("\\s*"))
return false ;
if (word.length() != expected.length())
return false ;
for(int idx = 0; idx < word.length(); idx++)
{
if (!isValidDigit(word.chatAt(idx), expected.charAt(idx)))
return false ;
}
return true ;
}
public boolean isValidDigit(char chr, char expected) {
String accepted ;
if (chr != expected)
{
accepted = acceptedChars.get(chr) ;
if (accepted == null)
return false ;
if (accepted.indexOf(chr) < 0)
return false ;
}
return true ;
}

Categories

Resources