生成有效数组的最少交换次数
难度:
标签:
题目描述
代码结果
运行时间: 47 ms, 内存: 28.7 MB
/*
* Problem: Minimum Swaps to Make Array Increasing
* Given an array nums, you are allowed to swap any two elements in the array.
* Return the minimum number of swaps needed to make the array strictly increasing.
*
* Approach:
* 1. Convert the array to a stream and sort it.
* 2. Map each element to its index in the sorted array.
* 3. Calculate the minimum swaps by finding cycles in the mapped indices.
*/
import java.util.*;
import java.util.stream.*;
public class MinimumSwapsStream {
public int minSwaps(int[] nums) {
int n = nums.length;
int[] sortedNums = Arrays.stream(nums).sorted().toArray();
Map<Integer, Integer> numToIndex = IntStream.range(0, n).boxed().collect(Collectors.toMap(i -> sortedNums[i], i -> i));
boolean[] visited = new boolean[n];
int swaps = 0;
for (int i = 0; i < n; i++) {
if (visited[i] || nums[i] == sortedNums[i]) continue;
int cycleSize = 0;
int x = i;
while (!visited[x]) {
visited[x] = true;
x = numToIndex.get(nums[x]);
cycleSize++;
}
if (cycleSize > 0) {
swaps += (cycleSize - 1);
}
}
return swaps;
}
public static void main(String[] args) {
MinimumSwapsStream solution = new MinimumSwapsStream();
int[] nums = {4, 3, 2, 1};
System.out.println(solution.minSwaps(nums)); // Output should be 2
}
}
解释
方法:
这个解法首先遍历一次数组,找出数组中的最小值和最大值以及它们的索引。最小值的索引记为 idx1,最大值的索引记为 idx2。这个解法的关键在于通过计算最小值和最大值的位置来确定最少的交换次数:1. 如果最小值在最大值之前出现(idx1 <= idx2),则直接计算两者到其应在的位置的距离差,即 idx1 (最小值移动到数组起始位置) 和 n-1-idx2 (最大值移动到数组末尾位置)。2. 如果最小值在最大值之后出现(idx1 > idx2),需要额外减去1,因为当最小值向前移动时,最大值的位置也会随之前移。这种情况下,我们在计算最大值移动到末尾的距离时多算了一次。
时间复杂度:
O(n)
空间复杂度:
O(1)
代码细节讲解
🦆
为什么在最小值在最大值后面出现时需要额外减去1?具体是如何影响交换次数的?
▷🦆
在遍历数组时,对于相同的最小值或最大值,选择更新索引的策略是什么?为什么最大值选择了`>=`而不仅是`>`?
▷🦆
这种计算最少交换次数的方法是否考虑了数组中可能存在的重复元素?重复元素会怎样影响结果?
▷🦆
如果数组已经是按照最小值到最大值排序的,这个算法是否还有效?它会返回正确的交换次数吗?
▷