【C/C++】670. 最大交换

249 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第32天,点击查看活动详情


题目链接:670. 最大交换

题目描述

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

提示:

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

示例 1:

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

示例 2:

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

整理题意

题目给定一个 [0,108][0, 10^8] 的非负整数,我们可以对这个整数中的任意两位进行一次交换,求进行一次操作后能够得到的最大值。

解题思路分析

方法一:暴力

首先能够想到的是暴力遍历所有可以交换的方法,取所有交换后的最大值即可。

贪心

我们从左到右遍历整数的每一位,如果在当前位右边有比当前位数字大的数字,我们将其与当前位进行交换即可。需要注意的是,如果右边有多位数字大于当前位数字,我们要选择最大的一位,且如果最大的一位有多个,我们需要选择最右边的一个。

具体实现

方法一:暴力

  1. 首先将整数转换成字符串进行处理;
  2. 双层循环遍历所有可以交换的方法;
  3. 利用一个变量记录交换后的最大值;
  4. 最后再将字符串转换成整数即可。

方法二:贪心

  1. 首先可以预处理出每一位的右边(包含自己)最大且最靠右的数字下标,从右到左记录遍历过的最大数字即可(需要注意当数字相同时需要取靠右的)
  2. 从左到右遍历每一位数字,当遇到当前位后面存在比当前位大的数字时,直接进行交换,然后跳出循环;
  3. 输出交换后的数字即可。

复杂度分析

  • 时间复杂度:
    • 暴力O(log3num)O(\log^3 \textit{num}),其中整数 num\textit{num} 为给定的数字。num\textit{num} 转换为十进制数,有 O(lognum)O(\log \textit{num}) 个数字,一共有 O(log2num)O(\log^2 \textit{num}) 种不同的交换方法,每种方法需要重新构造一个新的整数,需要的时间为 O(lognum)O(\log \textit{num}),因此总的时间复杂度为 O(log3num)O(\log^3 \textit{num})
    • 贪心O(lognum)O(\log \textit{num}),其中整数 num\textit{num} 为给定的数字。num\textit{num} 转换为十进制数,有 O(lognum)O(\log \textit{num}) 个数字,需要遍历一次所有的数字即可。
  • 空间复杂度:
    • 暴力O(lognum)O(\log \textit{num}),其中整数 num\textit{num} 为给定的数字。num\textit{num} 转换为十进制数,有 O(lognum)O(\log \textit{num}) 个数字,需要保存 num\textit{num} 所有的数字。
    • 贪心O(lognum)O(lognum),其中整数 num\textit{num} 为给定的数字。num\textit{num} 转换为十进制数,有 O(lognum)O(\log \textit{num}) 个数字,需要保存 num\textit{num} 所有的数字。

代码实现

暴力

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

贪心

class Solution {
public:
    int maximumSwap(int num) {
        string temp = to_string(num);
        int n = temp.size();
        int idx[n];
        idx[n - 1] = n - 1;
        for(int i = n - 2; i >= 0; i--){
            if(temp[i] <= temp[idx[i + 1]]){
                idx[i] = idx[i + 1];
            }
            else idx[i] = i;
        }
        for(int i = 0; i < n; i++){
            if(temp[i] < temp[idx[i]]){
                swap(temp[i], temp[idx[i]]);
                break;
            }
        }
        return stoi(temp);
    }
};

总结

  • 该题的难点在于贪心的方法;
  • 暴力搜索每一种交换方法比较容易想到,但是并不是最优解;
  • 在处理整数时,将其转换为字符串的形式进行处理比较方便。
  • 测试结果:

670. 最大交换.png

结束语

每个人都拥有时间,但不是每个人都懂的珍惜。别等到暮年才感叹年华的流逝。把握当下,不要把最精彩的人生过成最无奈的遗憾。新的一天,加油!