[Leetcode]最大交换-三种解法java

这个是力扣上面的一道题:点击此处跳转

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

示例 1 :

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

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

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

来源:力扣(LeetCode)

我会附上对官方给出了两种解答的理解,还有我自己的解答,重点写对贪心算法的理解。

  • 暴力法
  • 贪心算法
  • 第三种解法(非官方)
方法一:暴力法
数字最多只有 8 位,因此只有 28 个可用的互换。

算法:

我们将数字存储为长度为 len(num) 的列表。对于位置为 (i, j) 的每个候选交换,我们交换数字并记录组成的新数字是否大于当前答案,然后交换回来恢复原始数字。
唯一的细节可能是检查我们没有引入前导零。我们实际上不需要检查它,因为我们的原始数据没有。
Java

public class Solution {

    public int maximumSwap(int num) {
        String s = String.valueOf(num);
        int len = s.length();
        char[] charArray = s.toCharArray();
        int max = num;
        for (int i = 0; i < len; i++) {
            for (int j = i + 1; j < len; j++) {
                swap(charArray, i, j);//交换数字
                max = Math.max(max, Integer.parseInt(new String(charArray)));//记录组成新数字是否大于当前答案
                swap(charArray, i, j);//交换回来恢复原始数字
            }
        }
        return max;
    }

    private void swap(char[] charArray, int index1, int index2) {
        char temp = charArray[index1];
        charArray[index1] = charArray[index2];
        charArray[index2] = temp;
    }
}
复杂度分析

时间复杂度:O(N^3)其中 NN= 是输入数字的总位数。对于每对数字,我们最多花费 O(N) 的时间来比较最后的序列。
空间复杂度:O(N),存储在 A 中的信息。

来源:力扣(LeetCode)

例如有数 2746,max=2746
第一层外层循环(拿2依次与7、4、6作比较,得到最大的max值)
拿2与7作交换,得到数7246,与max作比较取最大值赋值给max,max=7246
拿2与4作交换,得到数4726,与max作比较取最大值赋值给max,max=7246

第二层外层循环(拿7依次与4、6作比较,得到最大的max值)
第三层外层循环(拿4与6作比较,得到最大的max值)
循环结束,得到最大的max值是7246,将其返回。


```java
方法二:贪心算法
算法:

我们将计算 last[d] = i,最后一次出现的数字d(如果存在)的索引i。
然后,从左到右扫描数字时,如果将来有较大的数字,我们将用最大的数字交换;如果有多个这样的数字,我们将用最开始遇到的数字交换。


public class Solution {

    public int maximumSwap(int num) {
        String s = String.valueOf(num);
        int len = s.length();
        char[] charArray = s.toCharArray();

        // 记录每个数字出现的最后一次出现的下标
        int[] last = new int[10];
        for (int i = 0; i < len; i++) {
            last[charArray[i] - '0'] = i;
        }

        // 从左向右扫描,找到当前位置右边的最大的数字并交换
        for (int i = 0; i < len - 1; i++) {
            // 找最大,所以倒着找
            for (int d = 9; d > charArray[i] - '0'; d--) {
                if (last[d] > i) {
                    swap(charArray, i, last[d]);
                    // 只允许交换一次,因此直接返回
                    return Integer.parseInt(new String(charArray));
                }
            }
        }
        return num;
    }

    private void swap(char[] charArray, int index1, int index2) {
        char temp = charArray[index1];
        charArray[index1] = charArray[index2];
        charArray[index2] = temp;
    }
}
复杂度分析

时间复杂度:O(N)。其中,N 是输入数字的总位数。每个数字最多只考虑一次。
空间复杂度:O(1)),last 使用的额外空间最多只有 10 个。


来源:力扣(LeetCode)

建立last数组(因为一个数字每位上可以是0~9任意数字,一共十个,所以last数组长度设为10)。
last数组存储每个数字出现的最后一次出现的下标,例如数字7897886中,将其转换为数组,数字“8”最后一次出现的下标是5,数字“7”最后一次出现的下标是3
数字7897886转换为数组

7897886的last数组
根据last数组,我们可以轻易知道每一个数字在数组中出现的最后一次的下标,
last[9]表示:数字9最后一次出现在数组下标为2的位置,chars[2]
last[8]表示:数字8最后一次出现在数组下标为5的位置,chars[5]

在这里插入图片描述
将两者比较大小,last[9]表示:数字9最后一次出现在数组下标为2的位置,chars[2],9大于7,所以交换位置,得到结果。

方法三:个人理解(非官方)
class Solution {
    public int maximumSwap(int num) {
        
       char[] chars=String.valueOf(num).toCharArray();
       char[] chars2=String.valueOf(num).toCharArray();
      
        for(int i=0;i<chars.length;i++){
            for(int j=0;j<chars.length-1-i;j++){
                if(chars2[j]<chars2[j+1]){
                    char k=chars2[j];
                    chars2[j]=chars2[j+1];
                    chars2[j+1]=k;}

            }
        }
        int a=0,c=0,flag=0;

        for(int i=0;i<chars.length;i++){
            if(chars[i]<chars2[i]) {
                a=chars2[i];
                c=i;
                flag=1;
                break;
            }}
        for(int i=chars.length-1;i>=0;i--){
            if(chars[i]==a&&flag==1){
                char k=chars[i];
                chars[i]=chars[c];
                chars[c]=k;}

        }

        return Integer.parseInt(new String(chars));
    }}

在这里插入图片描述
写两个数组,一个chars存储数字,一下chars2存储排序后的数组(这里使用的冒泡排序,冒泡忘的差不多了哈,见谅)。
例如chars:{2,6,9,8} 那么chars2:{9,8,6,2}
将其用冒泡排序,从大到小进行排序。

两个数组一起遍历,依次进行比较。当chars2[i]>chars[i]时,存储此时的最大值a以及下标c。同时设置了一个flag做标志,flag改变,并退出循环。
在这里插入图片描述
接着依次遍历chars,从右到左开始遍历,当满足条件(flag改变 并且 元素与a存储值相等时),交换元素。
个人比较粗心哈,如果有错误欢迎指正!


版权声明:本文为weixin_45668654原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。