leetcode
leetcode 551 ~ 600
最大交换

最大交换

难度:

标签:

题目描述

代码结果

运行时间: 15 ms, 内存: 16.0 MB


/*
 * Problem: Given a non-negative integer, you can swap at most once two digits of the number to get the maximum possible value. 
 * Solution: Convert the number to a character array, then find the highest possible number by swapping two digits. 
 * - Use Java Streams to manage the manipulation of the number as an array of digits. 
 * - Find the maximum digit that can be swapped to increase the number.
 */
 
import java.util.stream.IntStream;
 
public class Solution {
    public int maximumSwap(int num) {
        char[] digits = Integer.toString(num).toCharArray();
        int n = digits.length;
        int[] maxIndex = IntStream.range(0, n).toArray();
 
        // Record the position of the max digit to the right of each digit
        IntStream.range(0, n - 1).forEach(i -> {
            maxIndex[i] = IntStream.range(i + 1, n).boxed()
                    .max((j1, j2) -> digits[j1] - digits[j2])
                    .orElse(i);
        });
 
        // Find the first position where a larger digit can be swapped
        int pos = IntStream.range(0, n)
                .filter(i -> digits[i] < digits[maxIndex[i]])
                .findFirst()
                .orElse(-1);
 
        if (pos != -1) {
            // Swap
            char temp = digits[pos];
            digits[pos] = digits[maxIndex[pos]];
            digits[maxIndex[pos]] = temp;
        }
 
        return Integer.parseInt(new String(digits));
    }
}

解释

方法:

这个题解采用了枚举法的思路。对于一个给定的数字,我们可以枚举所有可能的交换位置(即任意两个数字交换),然后比较交换后的数字大小,取其中最大的一个作为最终答案。具体实现时,先将数字转化为字符串,然后使用两重循环枚举所有交换的可能性,每次交换后都更新答案为当前最大值。

时间复杂度:

O(n^2)

空间复杂度:

O(n)

代码细节讲解

🦆
题解中提到枚举所有可能的交换位置,但没有说明为什么不考虑多次交换,能否解释一下?
在这个问题中,我们的目标是通过一次交换得到可能的最大数字。多次交换虽然可以探索更多可能性,但实际上一次精确的交换就足以达到最大化的目的。这是因为多次交换并不一定能进一步增大数字,而且会大幅增加算法的复杂度。因此,为了保持算法的效率和简洁性,只考虑一次交换是合理的。
🦆
在两重循环中,内循环的起始位置为什么是从 i 开始而不是从 0 或 i+1 开始?这是否会影响到算法的效率或结果?
题解中的内循环起始位置应该是从0开始,而不是从i开始。这是因为我们需要考虑当前位置i与之前所有位置j(j < i)的交换可能性。如果内循环从i开始,那么我们将无法考虑将i位置的数字与之前位置的数字交换的情况。这个错误可能是题解中的笔误。正确的做法应当是内循环从0到i-1,以确保能枚举所有可能的交换,从而找到最优解。
🦆
题解中使用了`max`函数来比较和更新最大值,这样的操作是否会影响到算法的整体效率?
使用`max`函数来比较和更新最大值是这种枚举方法的一部分。尽管这种比较操作确实会增加执行时间,但在此算法框架下是必要的。每次交换后,使用`max`函数可以立即确定是否产生了一个更大的数字。然而,这种方法的效率主要受到两重循环的影响,因为时间复杂度为O(n^2),其中n是数字的位数。在这种情况下,使用`max`函数的效率影响相对较小。
🦆
在进行数字交换后,为什么要将数字恢复到原始状态而不是继续使用已交换的版本进行后续操作?
在每次交换后恢复数字到原始状态是为了确保每次交换都是独立的。这样做可以保证我们每次都是从未修改过的原始数字出发,独立考虑每种交换的结果。如果不恢复原始状态,那么后续的交换会在之前的交换基础上进行,这将导致无法正确评价单独一次交换的效果。此外,不恢复原始状态会使得问题复杂化,难以追踪每个交换的实际影响。

相关问题

拼接最大数

给你两个整数数组 nums1nums2,它们的长度分别为 mn。数组 nums1nums2 分别代表两个数各位上的数字。同时你也会得到一个整数 k

请你利用这两个数组中的数字中创建一个长度为 k <= m + n 的最大数,在这个必须保留来自同一数组的数字的相对顺序。

返回代表答案的长度为 k 的数组。

 

示例 1:

输入:nums1 = [3,4,6,5], nums2 = [9,1,2,5,8,3], k = 5
输出:[9,8,6,5,3]

示例 2:

输入:nums1 = [6,7], nums2 = [6,0,4], k = 5
输出:[6,7,6,0,4]

示例 3:

输入:nums1 = [3,9], nums2 = [8,9], k = 3
输出:[9,8,9]

 

提示:

  • m == nums1.length
  • n == nums2.length
  • 1 <= m, n <= 500
  • 0 <= nums1[i], nums2[i] <= 9
  • 1 <= k <= m + n