[LeetCode] 670. Maximum Swap 最大置換


 

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]

 

這道題給了一個數字,我們有一次機會可以置換該數字中的任意兩位,讓返回置換后的最大值,當然如果當前數字就是最大值,也可以選擇不置換,直接返回原數。那么最簡單粗暴的方法當然就是將所有可能的置換都進行一遍,然后更新結果 res,取其中較大的數字,這樣一定會得到置換后的最大數字,這里使用了整型數和字符串之間的相互轉換,參見代碼如下:

 

解法一:

class Solution {
public:
    int maximumSwap(int num) {
        string str = to_string(num);
        int res = num, n = str.size();
        for (int i = 0; i < n; ++i) {
            for (int j = i + 1; j < n; ++j) {
                swap(str[i], str[j]);
                res = max(res, stoi(str));
                swap(str[i], str[j]);
            }
        }
        return res;
    }
};

 

下面這種解法是一種更優解,思路是這樣的,由於希望置換后的數字最大,那么肯定最好的高位上的小數字和低位上的大數字進行置換,比如題目匯總的例子1。而如果高位上的都是大數字,像例子2那樣,很有可能就不需要置換。所以需要找到每個數字右邊的最大數字(包括其自身),這樣再從高位像低位遍歷,如果某一位上的數字小於其右邊的最大數字,說明需要調換,由於最大數字可能不止出現一次,這里希望能跟較低位的數字置換,這樣置換后的數字最大,所以就從低位向高位遍歷來找那個最大的數字,找到后進行調換即可。比如對於 1993 這個數:

1 9 9 3

9 9 9 3  (back數組)

9 9 1 3

我們建立好back數組后,從頭遍歷原數字,發現1比9小,於是從末尾往前找9,找到后一置換,就得到了 9913。

 

解法二:

class Solution {
public:
    int maximumSwap(int num) {
        string res = to_string(num), back = res;
        for (int i = back.size() - 2; i >= 0; --i) {
            back[i] = max(back[i], back[i + 1]);
        }
        for (int i = 0; i < res.size(); ++i) {
            if (res[i] == back[i]) continue;
            for (int j = res.size() - 1; j > i; --j) {
                if (res[j] == back[i]) {
                    swap(res[i], res[j]);
                    return stoi(res);
                }
            }
        }
        return stoi(res);
    }
};

 

下面這種解法建了十個桶,分別代表數字0到9,每個桶存該數字出現的最后一個位置,也就是低位。這樣從開頭開始遍歷數字上的每位上的數字,然后從大桶開始遍歷,如果該大桶的數字對應的位置大於當前數字的位置,說明低位的數字要大於當前高位上的數字,那么直接交換這兩個數字返回即可,其實核心思路跟上面的解法蠻像的,參見代碼如下:

 

解法三:

class Solution {
public:
    int maximumSwap(int num) {
        string str = to_string(num);
        vector<int> buckets(10, 0);
        for (int i = 0; i < str.size(); ++i) {
            buckets[str[i] - '0'] = i;
        }
        for (int i = 0; i < str.size(); ++i) {
            for (int k = 9; k > str[i] - '0'; --k) {
                if (buckets[k] <= i) continue;
                swap(str[i], str[buckets[k]]);
                return stoi(str);
            }
        }
        return num;
    }
};

 

我們也可以進一步的優化空間,實際上只關注兩個需要交換的位置即可,即高位上的小數字和低位上的大數字,分別用 pos1 和 pos2 指向其位置,均初始化為 -1,然后用一個指針 mx 指向低位最大數字的位置,初始化為 n-1,然后從倒數第二個數字開始往前遍歷,假如 str[i] 小於 str[mx],說明此時高位上的數字小於低位上的數字,是一對兒潛在可以交換的對象(但並不保證上最優解),此時將 pos1 和 pos2 分別賦值為 i 和 mx;若 str[i] 大於 str[mx],說明此時 str[mx] 不是低位最大數,將 mx 更新為 i。循環結束后,若 pos1 不為 -1,說明此時找到了可以交換的對象,而且找到的一定是最優解,直接交換即可,參見代碼如下:

 

解法四:

class Solution {
public:
    int maximumSwap(int num) {
        string str = to_string(num);
        int n = str.size(), mx = n - 1, pos1 = -1, pos2 = -1;
        for (int i = n - 2; i >= 0; --i) {
            if (str[i] < str[mx]) {
                pos1 = i;
                pos2 = mx;
            } else if (str[i] > str[mx]) {
                mx = i;
            }
        }
        if (pos1 != -1) swap(str[pos1], str[pos2]);
        return stoi(str);
    }
};

 

Github 同步地址:

https://github.com/grandyang/leetcode/issues/670

 

類似題目:

Create Maximum Number

 

參考資料:

https://leetcode.com/problems/maximum-swap/

https://leetcode.com/problems/maximum-swap/discuss/107068/Java-simple-solution-O(n)-time

https://leetcode.com/problems/maximum-swap/discuss/107153/simple-c-using-stdstring-and-stdstoi

https://leetcode.com/problems/maximum-swap/discuss/107084/C%2B%2B-3ms-O(n)-time-O(n)-space-DP-solution

https://leetcode.com/problems/maximum-swap/discuss/107073/C%2B%2B-one-pass-simple-and-fast-solution%3A-1-3ms-O(n)-time

 

LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM