邻位交换的最小次数

邻位交换的最小次数

题目描述

给你一个表示大整数的字符串 num ,和一个整数 k 。

如果某个整数是 num 中各位数字的一个 排列 且它的 值大于 num ,则称这个整数为 妙数 。可能存在很多妙数,但是只需要关注 值最小 的那些。

例如,num = "5489355142" :
第 1 个最小妙数是 "5489355214"
第 2 个最小妙数是 "5489355241"
第 3 个最小妙数是 "5489355412"
第 4 个最小妙数是 "5489355421"

返回要得到第k个 最小妙数 需要对 num 执行的 相邻位数字交换的最小次数 。

测试用例是按存在第k个最小妙数而生成的。

示例 1:

输入:num = "5489355142", k = 4
输出:2
解释:第 4 个最小妙数是 "5489355421" ,要想得到这个数字:
- 交换下标 7 和下标 8 对应的位:"5489355142" -> "5489355412"
- 交换下标 8 和下标 9 对应的位:"5489355412" -> "5489355421"

示例 2:

输入:num = "11112", k = 4
输出:4
解释:第 4 个最小妙数是 "21111" ,要想得到这个数字:
- 交换下标 3 和下标 4 对应的位:"11112" -> "11121"
- 交换下标 2 和下标 3 对应的位:"11121" -> "11211"
- 交换下标 1 和下标 2 对应的位:"11211" -> "12111"
- 交换下标 0 和下标 1 对应的位:"12111" -> "21111"

示例 3:

输入:num = "00123", k = 1
输出:1
解释:第 1 个最小妙数是 "00132" ,要想得到这个数字:
- 交换下标 3 和下标 4 对应的位:"00123" -> "00132"

提示:

2 <= num.length <= 1000
1 <= k <= 1000
num 仅由数字组成

思路分析

这题复杂在于需要分为两步才能得出答案
第一步需要寻找第K个妙数
第二步寻找变化为这个妙数的步数

两步的算法都不简单,在编写的时候还会不断怀疑是不是这样的,但是只要理清楚思路,计算好复杂度,就不用过于担心是不是正确的思路

寻找第K个妙数

从右到左依次入栈,并记录最大元素m,

如果最大元素大于当前array[i]的值,说明可以变得更大,我们将array[i]也入栈

从i+1位置依次出栈 索引递增的放到数组中 ,除了比array[i]稍大的元素放到i的位置上

例如我们栈中元素为 5,6,9。array[i]=4的话,我们不应该用9放到array[i],用5来替换

我们栈中元素为 5,6,9。array[i]=5的话,我们不应该用9或5放到array[i],用6来替换

交换几步可以让两者相同(本文重点)

随意的交换可能反而导致交换不是最小的

交换思路

我们依次保证array.length-1 到 0的位置是相同的,不会使交换次数增多

image.png

类似于冒泡排序了

正确性证明

image.png

Code

class Solution {
    public int getMinSwaps(String num, int k) {
        String copy=num;
        char[] chars=num.toCharArray();
        //得到第k个妙数
        while (k>0){
            PriorityQueue<Integer>queue=new PriorityQueue<>();
            int maxVauke=-1;
            for (int i = chars.length-1; i >=0 ; i--) {
                if(maxVauke<=chars[i]-'0'){
                    queue.add(chars[i]-'0');
                    maxVauke=Math.max(maxVauke,chars[i]-'0');
                }else {
                    boolean flag=true;
                    int temp=chars[i]-'0';
                    queue.add(chars[i]-'0');
                    for (int j = i+1; j <=chars.length-1 ; j++) {
                        if(flag&&queue.peek()>temp){
                            flag=false;
                            chars[i]=(char) (queue.poll()+'0');
                        }
                        chars[j]=(char) (queue.poll()+'0');
                    }
                    if(flag){
                        chars[i]=(char) (queue.poll()+'0');
                    }
                    break;
                }
            }
            k--;
            //System.out.println(Arrays.toString(chars));
        }
        char[] chars1=copy.toCharArray();
        //System.out.println(Arrays.toString(chars));
        //System.out.println(Arrays.toString(chars1));
        StringBuffer target=new StringBuffer();
        StringBuffer begin=new StringBuffer(copy);
        for (int i = 0; i < chars.length; i++) {
            target.append(chars[i]);
        }

        return beginToTarget(begin,target);
    }
    
    //计算变化步骤
    public int beginToTarget(StringBuffer begin,StringBuffer target){
        //System.out.println(begin+"  "+target);
        if(begin.length()==0)return 0;
        if(begin.charAt(begin.length()-1)==target.charAt(target.length()-1)){
            begin.deleteCharAt(begin.length()-1);
            target.deleteCharAt(target.length()-1);
            return beginToTarget(begin,target);
        }else {
            int count=0;
            for (int i = target.length()-1; i >=0 ; i--) {
                if(target.charAt(i)!=begin.charAt(begin.length()-1)){
                    count++;
                }else {
                    begin.deleteCharAt(begin.length()-1);
                    target.deleteCharAt(i);
                    return beginToTarget(begin,target)+count;
                }
            }
            return 0;
        }
    }
    
}

输入

"5489355142"
4

输出

2
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值