Maximum Swap LT670

 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:

    1. 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 }

猜你喜欢

转载自www.cnblogs.com/taste-it-own-it-love-it/p/10657870.html