https://zhengxucoding.wordpress.com/2015/04/19/minimum-number-formed-by-deleting-k-digits/
Problem: Please get the least number after deleting k digits from the input number. For example, if the input number is 24635, the least number is 23 after deleting 3 digits.
If there are digits who are greater than the next one, delete the first digit. If all digits in the number are increasingly sorted, delete the last digit gets deleted. The process repeats until the required k digits are deleted.
Now we get the rules to delete digits to get the least remaining number: If there are digits who are greater than the next one, delete the first digit. If all digits in the number are increasingly sorted, delete the last digit gets deleted. The process repeats until the required k digits are deleted.
http://massivealgorithms.blogspot.com/2015/06/lintcode-delete-digits-neverlandly.html
Read full article from Coding Interview Questions: No. 48 - Least Number after Deleting Digits
Problem: Please get the least number after deleting k digits from the input number. For example, if the input number is 24635, the least number is 23 after deleting 3 digits.
If there are digits who are greater than the next one, delete the first digit. If all digits in the number are increasingly sorted, delete the last digit gets deleted. The process repeats until the required k digits are deleted.
However, there are cases where we can not just select the minimum digit. For example, N = 32514, K = 2. We need to keep 3 digits. The most-left digit can not be 1 because we do no have enough digit to keep.
So our finding is that each time, we select a minimum digit such that there still have enough digits to keep. In the example where N = 32514 and K = 2, we need to keep 3 digits. First, we find the minimum of [3, 2, 5] because we need to have at least 2 digits on the right. It is 2. Then, we will find the minimum of [5, 1] because we need to find after the digit 2 and stop at 1 to keep 1 digit. After selecting 1 to keep, finally there is one selection, i.e., 4, to decide. Thus the minimum number can be obtained is 214.
public static String find(String input, int numDigitsToDelete){ if (numDigitsToDelete == 0){ return input; } else if (numDigitsToDelete >= input.length()){ return ""; } int numDigitLeft = input.length() - numDigitsToDelete; char[] result = new char[numDigitLeft]; int start = 0; int end = 0; for (int i = numDigitLeft; i >= 1; i--){ end = input.length() - i; int minIndex = getMinIndex(input, start, end); //update the digit to keep result[numDigitLeft - i] = input.charAt(minIndex); //update start for next windows start = minIndex + 1; } return String.valueOf(result);}private static int getMinIndex(String input, int start, int end){ char min = input.charAt(start); int minIndex = start; for (int i = start + 1; i <= end; i++){ //make sure compute the first (most left) if (input.charAt(i) < min){ min = input.charAt(i); minIndex = i; } } return minIndex;}7: public String generateLowestNumber(String S, int K) {
8: if (S == null || K > S.length()) {
9: return "";
10: }
11: // removing K digits is the same as keeping N - K digits
12: int add = S.length() - K; // the number of characters to add.
13: char[] lowest = new char[add];
14: // convert the input into an array of digits
15: int[] digits = new int[S.length()];
16: for (int i = 0; i < digits.length; i++) {
17: digits[i] = S.charAt(i) - '0';
18: }
19: int index = 0;
20: int[] closest = new int[S.length()];
21: closest[digits.length - 1] = -1;
22: for (int i = digits.length - 2; i >= 0; i--) {
23: int j = i + 1;
24: while (j != -1 && digits[i] <= digits[j]) {
25: j = closest[j];
26: }
27: closest[i] = j;
28: }
29: for (int i = 0; i < add; i++) {
30: int j = index;
31: while (j != -1 && j <= (digits.length - (add - i))) {
32: lowest[i] = (char) (digits[j] + (int) '0');
33: index = j;
34: j = closest[j];
35: }
36: index++;
37: }
38: return String.valueOf(lowest);
39: }
Coding Interview Questions: No. 48 - Least Number after Deleting DigitsNow we get the rules to delete digits to get the least remaining number: If there are digits who are greater than the next one, delete the first digit. If all digits in the number are increasingly sorted, delete the last digit gets deleted. The process repeats until the required k digits are deleted.
public static String getLeastNumberDeletingDigits_1(String number, int k) {
String leastNumber = number;
while(k > 0 && leastNumber.length() > 0) {
int firstDecreasingDigit = getFirstDecreasing(leastNumber);
if(firstDecreasingDigit >= 0) {
leastNumber = removeDigit(leastNumber, firstDecreasingDigit);
}
else {
leastNumber = removeDigit(leastNumber, leastNumber.length() - 1);
}
--k;
}
return leastNumber;
}
private static int getFirstDecreasing(String number) {
for(int i = 0; i < number.length() - 1; ++i) {
int curDigit = number.charAt(i) - '0';
int nextDigit = number.charAt(i + 1) - '0';
if(curDigit > nextDigit) {
return i;
}
}
return -1;
}
private static String removeDigit(String number, int digitIndex) {
String result = "";
if(digitIndex > 0) {
result = number.substring(0, digitIndex);
}
if(digitIndex < number.length() - 1) {
result += number.substring(digitIndex + 1);
}
return result;
}
Optimization: Save the start index for the next round of search for the first decreasing digit
In the method getFirstDecreasing above to get the first digit which is greater than the next one, we always start from the first digit. Is it necessary to start over in every round of search?
The answer is no. If the ith digit is the first digit which is greater than the next one, all digits before the ith digit are increasingly sorted. The (i-1)th digit might be less than the (i+1)th digit, the next digit of the (i-1)th digit after the ith digit is deleted. Therefore, it is safe to start from the (i-1)th digit in the next round of search.
With this optimization strategy, the efficiency gets improved from O(n*k) to O(n), if the length of the input number has n digits and k digits are deleted.
class DecreasingResult {
public int firstDecreasing;
public int nextStart;
}
public static String getLeastNumberDeletingDigits_2(String number, int k) {
String leastNumber = number;
int start = 0;
while(k > 0 && leastNumber.length() > 0) {
DecreasingResult result = getNextDecreasing(leastNumber, start);
if(result.firstDecreasing >= 0) {
leastNumber = removeDigit(leastNumber, result.firstDecreasing);
}
else {
leastNumber = removeDigit(leastNumber, leastNumber.length() - 1);
}
start = result.nextStart;
--k;
}
return leastNumber;
}
private static DecreasingResult getNextDecreasing(String number, int start) {
int firstDecreasing = -1;
int nextStart;
for(int i = start; i < number.length() - 1; ++i) {
int curDigit = number.charAt(i) - '0';
int nextDigit = number.charAt(i + 1) - '0';
if(curDigit > nextDigit) {
firstDecreasing = i;
break;
}
}
if(firstDecreasing == 0) {
nextStart = 0;
}
else if (firstDecreasing > 0) {
nextStart = firstDecreasing - 1;
}
else { // the value of nextStart doesn't matter
nextStart = number.length();
}
DecreasingResult result = new DecreasingResult();
result.firstDecreasing = firstDecreasing;
result.nextStart = nextStart;
return result;
}
http://www.geeksforgeeks.org/build-lowest-number-by-removing-n-digits-from-a-given-number/
since we can at most delete n characters, thus for any of (n+1) characters, there must be at least 1 character not being deleted.
And we process from left because of most significant bit is in left.
The idea is based on the fact that a character among first (n+1) characters must be there in resultant number. So we pick the smallest of first (n+1) digits and put it in result, and recur for remaining characters. Below is complete algorithm.
Initialize result as empty string
res = ""
buildLowestNumber(str, n, res)
1) If n == 0, then there is nothing to remove.
Append the whole 'str' to 'res' and return
2) Let 'len' be length of 'str'. If 'len' is smaller or equal
to n, then everything can be removed
Append nothing to 'res' and return
3) Find the smallest character among first (n+1) characters
of 'str'. Let the index of smallest character be minIndex.
Append 'str[minIndex]' to 'res' and recur for substring after
minIndex and for n = n-minIndex
buildLowestNumber(str[minIndex+1..len-1], n-minIndex).
void buildLowestNumberRec(string str, int n, string &res){ // If there are 0 characters to remove from str, // append everything to result if (n == 0) { res.append(str); return; } int len = str.length(); // If there are more characters to remove than string // length, then append nothing to result if (len <= n) return; // Find the smallest character among first (n+1) characters // of str. int minIndex = 0; for (int i = 1; i<=n ; i++) if (str[i] < str[minIndex]) minIndex = i; // Append the smallest character to result res.push_back(str[minIndex]); // substring starting from minIndex+1 to str.length() - 1. string new_str = str.substr(minIndex+1, len-minIndex); // Recur for the above substring and n equals to n-minIndex buildLowestNumberRec(new_str, n-minIndex, res);}// A wrapper over buildLowestNumberRec()string buildLowestNumber(string str, int n){ string res = ""; // Note that result is passed by reference buildLowestNumberRec(str, n, res); return res;}http://massivealgorithms.blogspot.com/2015/06/lintcode-delete-digits-neverlandly.html
Read full article from Coding Interview Questions: No. 48 - Least Number after Deleting Digits