邻位交换的最小次数
题目描述
给你一个表示大整数的字符串 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的位置是相同的,不会使交换次数增多
类似于冒泡排序了
正确性证明
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