邻位交换的最小次数
难度:
标签:
题目描述
代码结果
运行时间: 116 ms, 内存: 17.4 MB
/*
* Similar to the traditional Java solution, we can use Java streams
* to manipulate and find permutations, and then determine the required swaps.
*/
import java.util.*;
import java.util.stream.*;
public class SolutionStream {
public int getMinSwaps(String num, int k) {
char[] chars = num.toCharArray();
String target = IntStream.range(0, k).mapToObj(i -> {
nextPermutation(chars);
return new String(chars);
}).reduce((first, second) -> second).orElse(num);
chars = num.toCharArray();
int swaps = 0;
for (int i = 0; i < num.length(); i++) {
if (chars[i] != target.charAt(i)) {
int j = i;
while (chars[j] != target.charAt(i)) {
j++;
}
while (j > i) {
swap(chars, j, j - 1);
j--;
swaps++;
}
}
}
return swaps;
}
private void nextPermutation(char[] chars) {
int i = chars.length - 2;
while (i >= 0 && chars[i] >= chars[i + 1]) {
i--;
}
if (i >= 0) {
int j = chars.length - 1;
while (chars[j] <= chars[i]) {
j--;
}
swap(chars, i, j);
}
reverse(chars, i + 1);
}
private void swap(char[] chars, int i, int j) {
char temp = chars[i];
chars[i] = chars[j];
chars[j] = temp;
}
private void reverse(char[] chars, int start) {
int end = chars.length - 1;
while (start < end) {
swap(chars, start, end);
start++;
end--;
}
}
}
解释
方法:
解决这个问题涉及两个主要步骤:1. 找到给定数字字符串的第k个字典序更大的排列。2. 计算从原始字符串到该排列通过相邻交换得到的最小次数。首先,使用'kthNextPermutation'函数来获取所需的排列,此函数实现了对给定数组的下一个排列算法,并能够处理有重复数字的情况。之后,利用索引映射和树状数组(Binary Indexed Tree, BIT),来计算把原数组转换到目标排列需要的最小交换次数。树状数组用于高效计算前缀和,以此来快速得出每次交换的次数。
时间复杂度:
O(n log n)
空间复杂度:
O(n)
代码细节讲解
🦆
在`kthNextPermutation`函数中,如何确保找到的排列是第k个字典序更大的排列而非仅仅是下一个?
▷🦆
函数中使用到了树状数组(BIT),为什么选择这种数据结构而不是其他例如线段树或简单数组?
▷🦆
在计算最小交换次数时,为什么需要使用索引映射和树状数组来计算前缀和?能否简单解释其原理和步骤?
▷🦆
能否详细解释一下`al`数组在解决方案中的作用是什么以及它是如何构建的?
▷