Given a non-negative integer, you could swap two digits at most once to get the maximum valued number. Return the maximum valued number you could get.
Example 1:
Input: 2736 Output: 7236 Explanation: Swap the number 2 and the number 7.
Example 2:
Input: 9973 Output: 9973 Explanation: No swap.
Note:
- The given number is in the range [0, 108]
Idea 1. To get a biggest digit for each position, the digit need to swap with the biggest in the number, since it aims to get the maximum valued number, the digit (digits[i]) need to swap with the biggest digit on the right(digits[j] > digits[i], j > i), the digit needs to be the leftmost one which has a bigger digit on the right side. Since needs index to swap, build the maxIndex array. 从右往左建一个maxIndexArray, 再从左到右遍历 找到第一个digits[i] < digits[maxIndex[i]], swap(i, maxIndex[i]).
Note: right most maxIndex, if there are duplicates like 27736, 77236 > 72736
Time complexity: O(n) 2 scan, if string construction is O(n)
Space complexity: O(n)
1 class Solution { 2 public int maximumSwap(int num) { 3 char[] digits = Integer.toString(num).toCharArray(); 4 int[] maxIndex = new int[digits.length]; 5 6 maxIndex[digits.length-1] = digits.length-1; 7 for(int i = digits.length-2; i >=0; --i) { 8 maxIndex[i] = i; 9 if(digits[maxIndex[i]] - '0' <= digits[maxIndex[i+1]] - '0') { 10 maxIndex[i] = maxIndex[i+1]; 11 } 12 } 13 14 for(int i = 0; i < digits.length; ++i) { 15 if(digits[i] - '0' < digits[maxIndex[i]] - '0') { 16 char c = digits[i]; 17 digits[i] = digits[maxIndex[i]]; 18 digits[maxIndex[i]] = c; 19 break; 20 } 21 } 22 23 return Integer.parseInt(new String(digits)); 24 } 25 }
Idea 1.a, to avoid maxIndex array, record the maxIndex on the way, 1 scan from right to left
1 class Solution { 2 private void swap(char[] digits, int leftIndex, int rightIndex) { 3 char c = digits[leftIndex]; 4 digits[leftIndex] = digits[rightIndex]; 5 digits[rightIndex] = c; 6 } 7 public int maximumSwap(int num) { 8 char[] digits = Integer.toString(num).toCharArray(); 9 10 int leftIndex = -1, rightIndex = -1; 11 int maxIndex = digits.length-1; 12 for(int i = digits.length-1; i >=0; --i) { 13 if(digits[i] > digits[maxIndex]) { 14 maxIndex = i; 15 } 16 else if(digits[i] < digits[maxIndex]) { 17 leftIndex = i; 18 rightIndex = maxIndex; 19 } 20 } 21 22 if(leftIndex == -1) { 23 return num; 24 } 25 26 swap(digits, leftIndex, rightIndex); 27 28 return Integer.parseInt(new String(digits)); 29 } 30 }
Idea 1.c. Remove the use of toCharArray, convert to digit on the way from right to left.
Time complexity: O(n)
Space complexity: O(1)
1 class Solution { 2 public int maximumSwap(int num) { 3 int leftDigit = -1, rightDigit = -1; 4 int leftBase = 0, rightBase = 0; 5 int curr = num; 6 7 int maxDigit = -1; 8 int maxBase = 0; 9 int base = 1; 10 while(curr != 0) { 11 int digit = curr % 10; 12 13 if(digit > maxDigit) { 14 maxDigit = digit; 15 maxBase = base; 16 } 17 else if(digit < maxDigit) { 18 leftDigit = digit; 19 leftBase = base; 20 rightDigit = maxDigit; 21 rightBase = maxBase; 22 } 23 base = base * 10; 24 curr = curr/10; 25 } 26 27 if(leftDigit == -1) { 28 return num; 29 } 30 31 num = num - leftDigit*leftBase - rightDigit*rightBase 32 + leftDigit* rightBase + rightDigit * leftBase; 33 34 return num; 35 } 36 }
Idea 2. 官方的妙法,数字只有0-9,建立一个数组记录每个数字出现在最右边的index(从左到右扫), 再从左到右扫,寻找第一个digits[i] < last[d] (d > digits[i] and last[d] > i), swap(digits, i, last[d]).
1 class Solution { 2 private void swap(char[] digits, int i, int j) { 3 char c = digits[i]; 4 digits[i] = digits[j]; 5 digits[j] = c; 6 } 7 public int maximumSwap(int num) { 8 char[] digits = Integer.toString(num).toCharArray(); 9 10 int[] last = new int[10]; 11 for(int i = 0; i < digits.length; ++i) { 12 last[digits[i] - '0'] = i; 13 } 14 15 for(int i = 0; i < digits.length; ++i) { 16 for(int d = 9; d > digits[i] - '0'; --d) { 17 if(last[d] > i) { 18 swap(digits, i, last[d]); 19 return Integer.valueOf(new String(digits)); 20 } 21 } 22 } 23 24 return num; 25 } 26 }
Idea 3. 虽然也感觉和LT31 Next Permutation有相似的,没有找出规律,网上看到的妙法,从左到右找到第一个valley, 继续valley后找到最大值作为要交换的rightIndex, 然后再从左到右找一个小于最大值的作为leftIndex, swap(digits, leftIndex, rightIndex); LT31是从右到左找第一个peak, peak的左边是rightIndex, 再从右到左找第一个比digits[rightIndex]小的作为leftIndex, 最后交换就是了.
Note. duplicates, rightMost index like 27736, 77236 > 72736, 又犯了错,下次记住这个test case啊
1 class Solution { 2 private void swap(char[] digits, int i, int j) { 3 char c = digits[i]; 4 digits[i] = digits[j]; 5 digits[j] = c; 6 } 7 public int maximumSwap(int num) { 8 char[] digits = Integer.toString(num).toCharArray(); 9 10 int rightIndex = 1; 11 while(rightIndex < digits.length && digits[rightIndex-1] >= digits[rightIndex]) { 12 ++rightIndex; 13 } 14 15 if(rightIndex == digits.length) { 16 return num; 17 } 18 19 for(int i = rightIndex+1; i < digits.length; ++i) { 20 if(digits[i] >= digits[rightIndex]) { 21 rightIndex = i; 22 } 23 } 24 25 for(int i = 0; i < digits.length; ++i) { 26 if(digits[i] < digits[rightIndex]) { 27 swap(digits, i, rightIndex); 28 break; 29 } 30 } 31 32 return Integer.parseInt(new String(digits)); 33 } 34 }