Expedia Interview Question
SDE-2sCountry: India
Interview Type: Phone Interview
function nextBiggest(val){
var a = val.toString();
for(var i = a.length - 1; i >= 0; i--){
var b = parseInt(a.charAt(i));
if(b == 0){
continue;
}
for(var z = i - 1; z >= 0; z--){
var l = parseInt(a.charAt(z));
if(l < b){
a = a.replaceAt(i, l.toString());
a = a.replaceAt(z, b.toString());
return a;
}
}
}
return a;
}
This solution seems work in O(L^2) worst case where L is a length of a number. For example consider the number: 8988...8877..7766..6655..5544..4433..3322..2211..1100..00
For every digit except 9 you will go till the beginning of the number trying to find something less than this digit, and fail. And only digit 9 will succeed.
Take the last digit.
Find the first digit on the left that's smaller.
Swap
All digits to the right of the swapped digits to be sorted in ascending order
Interesting thing is that this incorrect solution is voted up, while the correct O(length) algorithm I proposed is voted down. People don't even understand how to judge solutions.
Correct algorithm: We swap the rightmost digit, which has larger digits to its right, with the next highest digit value. (for example, in 15864, the rightmost digit which has larger digits to its right is 5, and the next highest digit is 6, so we get 16854).
Then simply sort the digits to its right in ascending order (in this case, the last 3 digits, so we get 16458).
Complexity O(N log N), space used O(1) if sorting done in-place.
Code in python:
def next_perm(l):
k=len(l)-1
pos=None
while k>0:
k-=1
if l[k]<l[k+1]:
pos=k
break
if pos:
k=len(l)-1
while k>0:
if l[k]>l[pos]:
break
k-=1
l[pos], l[k] = l[k], l[pos]
l[pos+1:]=sorted(l[pos+1:])
def main():
l=[2,1,8,7,6,5]
print l
next_perm(l)
print l
if __name__ == "__main__":
main()
Traverse the given number from rightmost digit, keep traversing till you find a digit which is smaller than the previously traversed digit.
Swap the digits.
Sort the digits right to the swapped index.
String findNextNumber(char[] n)
{
String next = null;
char lastDigit = n[n.length -1];
int i = n.length -2;
for( ; i >= 0 ; i -- )
{
if(n[i] < lastDigit){
{
swap(n, i, n.length -1);
sortArray(n, i+1);
next = String.valueOf(n);
break;
}
}
}
return next;
}
Take the last digit.
Find the first digit on the left that's smaller.
Swap
All digits to the right of the swapped digits to be sorted in ascending order
This is not quite right. For example your solution would fail on this input: 5981. The proper answer is 8159. But "Take the last digit. Find the first digit on the left that's smaller" will find nothing because there is no digit on the left that's smaller than the last (1 is the smallest digit here).
The logic is correct. You move onto the second last digit if nothing is found for the last digit and so on.
The initial post doesn't state this idea. It says nothing about what would happen if we don't find anything for the last digit.
You're right, akash.gpta, but... This solution can take O(L^2) time where L is a lenght of the number. Check your algo on the following number: 8988...8877..7766..6655..5544..4433..3322..2211..1100..00
We can do better - in O(L) time.
Make a queue to store digits
Iterate through the digits in the number starting at the rightmost position (least significant)
add the digit to the queue
if there is a digit to the left
if the digit to the left is smaller than the head of the queue
put the left digit in a temp
replace the left position with the head of the queue
put the temp in the current digit position
and output the remaining integers from the queue
return the new number
else return -1
Complexity is O(n) where n is the number of digits and Memory is O(n). It could be made memory O(1) if the processing was done in more of a String char approach, but I thought moving to arrays and string / char conversions would be slower.
public static int nextLarger(int val){
if(val < 12){
return -1;
}
Queue<Integer> queue = new LinkedList<Integer>();
queue.add(val%10);
val /= 10;
while(val > 0){
int nextVal = val %10;
val /= 10;
if(nextVal < queue.peek()){
val = val * 10 + queue.remove();
val = val * 10 + nextVal;
while(queue.peek() != null){
val = val * 10 + queue.remove();
}
return val;
}
queue.add(nextVal);
}
return -1;
}
Algorithm
I) Traverse the given number from rightmost digit, keep traversing till you find a digit which is smaller than the previously traversed digit. For example, if the input number is “534976”, we stop at 4 because 4 is smaller than next digit 9. If we do not find such a digit, then output is “Not Possible”.
II) Now search the right side of above found digit ‘d’ for the smallest digit greater than ‘d’. For “534976″, the right side of 4 contains “976”. The smallest digit greater than 4 is 6.
III) Swap the above found two digits, we get 536974 in above example.
IV) Now sort all digits from position next to ‘d’ to the end of number. The number that we get after sorting is the output. For above example, we sort digits in bold 536974. We get “536479” which is the next greater number for input 534976.
Notice that in step IV you don't have to sort those digits. Since they are descending (by construction), you can just reverse those. And you get a linear algorithm.
pavelkalinnikov yaa you are right . we do not need to sort we just need to reverse that range.. tanq bro for info :)
package Companies.Expedia.Strings;
public class FindNextBigNumber {
public static void main(String[] args) {
String str = "871265";
int index = checkIfPossible(str);
if(index == -1) {
System.out.println("This is the biggest number");
return;
}
else {
str = calculateNextBig(str, index);
System.out.println(str);
}
}
public static int checkIfPossible(String str) {
int index = -1;
for(int i = str.length() - 1; i > 0; i--) {
if(str.charAt(i) > str.charAt(i - 1)) {
index = i - 1;
return index;
}
}
return index;
}
public static String calculateNextBig(String str, int index) {
int nextHighestIndex = index + 1;
for(int i = nextHighestIndex + 1; i < str.length(); i++) {
if((Character.getNumericValue(str.charAt(i)) < Character.getNumericValue(str.charAt(nextHighestIndex))) &&
(Character.getNumericValue(str.charAt(i)) > Character.getNumericValue(str.charAt(index)))) {
nextHighestIndex = i;
}
}
str = swap(str, index, nextHighestIndex);
str = reverseRemaining(str, index + 1);
return str;
}
public static String swap(String str, int index, int nextHighestIndex) {
StringBuilder s = new StringBuilder(str);
char temp = s.charAt(index);
s.setCharAt(index, s.charAt(nextHighestIndex));
s.setCharAt(nextHighestIndex, temp);
return s.toString();
}
public static String reverseRemaining(String str, int index) {
int start = index;
int end = str.length() - 1;
while(start < end) {
str = swap(str, start, end);
start++;
end--;
}
return str;
}
}
int function(int number) {
StringBuilder str = new StringBuilder(String.valueOf(number));
for (int i = str.length() - 1; i > 0; i--) {
if (Integer.valueOf(str.charAt(i) - '0') > Integer.valueOf(str.charAt(i - 1) - '0')) {
int index = str.length() - 1;
while (index > (i - 1)) {
if (Integer.valueOf(str.charAt(index) - '0') > Integer.valueOf(str
.charAt(i - 1) - '0')) {
break;
}
index--;
}
char temp = str.charAt(i - 1);
str.replace(i - 1, i, String.valueOf(str.charAt(index)));
str.replace(index, index + 1, String.valueOf(temp));
int j = str.length() - 1;
while (j > i) {
temp = str.charAt(j);
str.replace(j, j + 1, String.valueOf(str.charAt(i)));
str.replace(i, i + 1, String.valueOf(temp));
i++;
j--;
}
break;
}
}
return Integer.valueOf(str.toString());
}
This is a "next permutation" problem and the algorithm for solving it is as follows:
- Pavel Kalinnikov November 12, 20140. Let us assume that digits are numbered 0..(L-1) starting from the lowest digits.
1. Find the first (starting from the lowest) digit d[i] such as:
d[i] < d[i-1], 0 < i < L
2. Find the first (starting from the lowest) digit d[j], which is greater than d[i]:
d[j] > d[i], 0 <= j < i
3. Swap(d[i], d[j])
4. Reverse digits from 0 to (i-1)
The complexity of this algo is O(L)