【670. 最大交换】

来源:力扣(LeetCode)

描述:

给定一个非负整数,你至多可以交换一次数字中的任意两位。返回你能得到的最大值。

示例 1 :

输入: 2736
输出: 7236
解释: 交换数字2和数字7

示例 2 :

输入: 9973
输出: 9973
解释: 不需要交换。

注意:

  • 给定数字的范围是 [0, 108]

方法一:直接遍历

由于对于整数 num 的十进制数字位长最长为 8 位,任意两个数字交换一次最多有 28 种不同的交换方法,因此我们可以尝试遍历所有可能的数字交换方法即可,并找到交换后的最大数字即可。(类似选择排序,但是只能交换一次。)

  • 我们将数字存储为长度为 n 的列表,其中 n 为整数 num 的十进制位数的长度。对于位置为 (i, j) 的每个候选交换,我们交换数字并记录组成的新数字是否大于当前答案;
  • 对于前导零的问题,我们也不需要特殊处理。
  • 由于数字只有 8 位,所以我们不必考虑交换后溢出的风险;

代码:

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

执行用时:0 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗:5.9 MB, 在所有 C++ 提交中击败了10.84%的用户
复杂度分析
时间复杂度:O(log2num),其中整数 num 为给定的数字。num 转换为十进制数,有 O(lognum) 个数字,一共有 O(log2 num) 种不同的交换方法。
空间复杂度:O(lognum),其中整数 num 为给定的数字。 num 转换为十进制数,有 O(lognum) 个数字,需要保存 num 所有的数字。

方法二:贪心

设整数 num 从右向左的数字分别为(d0, d1, d2, ⋯, dn−1),则此时我们可以知道:

num
假设我们对位于 j, k 位上的数字进行交换,其中满足 0 ≤ j < k < n,则可以知道交换后的值 val 如下:

val
根据以上等式我们可以看出,若使得 \textit{val}val 的值最大,应依次满足如下条件:

  • 最优的交换一定需要满足 dj > dk

  • 在满足 dj > dk 时,应该保证索引 k 越大从而使得数字 val 越大;

  • 在同样大小的数字 dk 时,应使得数字 dj 越大从而使得 val 越大;

  • 在同样大小的数字 dj 时,应使得索引 j 越小从而使得 val 越大;

通过以上可以观察到右边越大的数字与左边较小的数字进行交换,这样产生的整数才能保证越大。因此我们可以利用贪心法则,尝试将数字中右边较大的数字与左边较小的数字进行交换,这样即可保证得到的整数值最大。具体做法如下:

  • 我们将从右向左扫描数字数组,并记录当前已经扫描过的数字的最大值的索引为 maxId 且保证 maxId 越靠近数字的右侧,此时则说明 charArray[maxId] 则为当前已经扫描过的最大值。

  • 如果检测到当前数字 charArray[i] < charArray[maxId],此时则说明索引 i 的右侧的数字最大值为 charArray[maxId],此时我们可以尝试将 charArray[i] 与 charArray[maxId] 进行交换即可得到一个比 num 更大的值。我们尝试记录当前可以交换的数对 (i, maxId),根据贪心法则,此时最左边的 i 构成的可交换的数对进行交换后形成的整数值最大。

代码:

class Solution {
public:
    int maximumSwap(int num) {
        string charArray = to_string(num);
        int n = charArray.size();
        int maxIdx = n - 1;
        int idx1 = -1, idx2 = -1;
        for (int i = n - 1; i >= 0; i--) {
            if (charArray[i] > charArray[maxIdx]) {
                maxIdx = i;
            } else if (charArray[i] < charArray[maxIdx]) {
                idx1 = i;
                idx2 = maxIdx;
            }
        }
        if (idx1 >= 0) {
            swap(charArray[idx1], charArray[idx2]);
            return stoi(charArray);
        } else {
            return num;
        }
    }
};

执行用时:0 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗:5.7 MB, 在所有 C++ 提交中击败了81.75%的用户
复杂度分析
时间复杂度:O(lognum),其中整数 num 为给定的数字。num 转换为十进制数,有 O(lognum) 个数字,需要遍历一次所有的数字即可。
空间复杂度:O(lognum),其中整数 num 为给定的数字。num 转换为十进制数,有 O(lognum) 个数字,需要保存 num 所有的数字。
author:LeetCode-Solution

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千北@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值