← 返回题目列表

最大交换如何用贪心得到最大数字?为什么要和最靠右的大数字交换?

中等 第 25 / 29 题 更新于 2026/08/01
贪心数组数字处理最大交换

简化版

最大交换只允许交换一次。贪心策略是从左到右找第一个能被右侧更大数字替换的位置;为了让结果最大,应选择右侧最大的数字,并且若有多个相同最大数字,选择最靠右的那个交换。

详细版

可以先记录每个数字 0..9 最后出现的位置。然后从左到右扫描当前位 d,尝试从 9 到 d+1 查找是否有更大数字出现在右侧。如果找到,就交换当前位和那个更大数字的最后位置,立即返回。

因为越靠左的位权越大,所以第一次能提升的位置最关键;同一个更大数字选择最靠右位置,能让被换下去的小数字尽量靠后。时间复杂度 O(10n),可视作 O(n)

完整版教学

一、为什么只关心最左边能提升的位置

数字大小由高位优先决定。只允许交换一次时,最划算的事情一定是尽量提升靠左的位置。比如 2736,把 27 换成 7236,比把后面的 36 换成 2763 大得多。

7236
2763
^ 第一位已经决定胜负

因此扫描时一旦找到某个位置能变大,就应该在这个位置完成交换并返回。

二、为什么要找右侧最大数字

对于当前位置 i,如果右侧有多个比它大的数字,当然应该换最大的。比如当前是 2,右侧有 79,换 9 得到的高位更大。

当前位可交换右侧数字最优选择
27、99
45、88

记忆钩子:一次交换要把“最靠左的坑”补到尽可能大。

这就是从 9 往当前数字上方枚举的原因。

三、为什么相同大数字选最靠右的

如果右侧有多个相同的最大数字,选择最靠右的那个更好。因为当前较小数字会被换到那个位置,放得越靠右,对整体影响越小。

num = 1993
交换第一个 1 和第一个 9:9193
交换第一个 1 和第二个 9:9913

显然 9913 更大,所以要记录每个数字最后出现的位置。

四、如何记录最后位置

数字只有 10 种,可以用长度为 10 的数组:

last[d] = 数字 d 最后一次出现的下标

例如 98368

last[8] = 4
last[9] = 0
last[3] = 2
last[6] = 3

扫描每个位置时,查看 9当前数字+1 是否存在于右侧即可。

五、代码模板

int maximumSwap(int num) {
    char[] arr = String.valueOf(num).toCharArray();
    int[] last = new int[10];
    for (int i = 0; i < arr.length; i++) {
        last[arr[i] - '0'] = i;
    }
    for (int i = 0; i < arr.length; i++) {
        int cur = arr[i] - '0';
        for (int d = 9; d > cur; d--) {
            if (last[d] > i) {
                char tmp = arr[i];
                arr[i] = arr[last[d]];
                arr[last[d]] = tmp;
                return Integer.parseInt(new String(arr));
            }
        }
    }
    return num;
}

last[d] > i 保证更大数字在当前位右侧。如果数字已经是降序,比如 9973,循环不会交换,直接返回原数。

六、用例子推演

num=2736

last[7]=1, last[6]=3, last[3]=2, last[2]=0
扫描 i=0,当前 2
从 9 查到 7,发现 last[7]=1 > 0
交换 2 和 7,得到 7236

num=1993

i=0,当前 1
last[9]=2
交换下标 0 和 2,得到 9913

这正体现了“右侧最大 + 最靠右”的双重选择。

七、常见误区与追问

  • 误区:交换全局最大和全局最小。 最小数字如果不在高位,交换未必最优。
  • 误区:相同最大数字选第一个。 应选最靠右的相同最大数字,让小数字尽量后移。
  • 误区:找到可交换后继续尝试后面位置。 最左提升位最重要,完成后应立即返回。
  • 追问:为什么复杂度是 O(n) 每位最多检查 10 个数字,常数为 10。
  • 追问:如果允许多次交换呢? 问题会变成排序或更复杂的交换约束,不再是这个贪心。
  • 追问:输入为 0 怎么办? 转成字符数组后不会交换,返回 0。

八、加强记忆

最大交换的口诀是“最左能变大,右侧找最大;相同选最右,交换就收手”。高位优先决定了为什么从左扫,最后位置数组决定了为什么能找最右最大数字。别做全局最大最小交换,那是这题最常见的误判。