当前位置: 面试刷题>> 使序列递增的最小交换次数 (经典算法题500道)


### 题目描述补充 题目:给定一个整数数组 `arr`,你可以交换任意两个相邻元素一次。请编写一个算法,找出使数组元素严格递增所需的最小交换次数。如果无法通过交换使得数组严格递增,则返回 `-1`。 ### 示例 - 输入:`arr = [3, 2, 3, 1]` - 输出:`2` - 解释:我们可以进行两次交换,先将 `3` 和 `2` 交换,得到 `[2, 3, 3, 1]`,再将 `3` 和 `1` 交换,得到 `[2, 1, 3, 3]`,此时数组是严格递增的。 ### 解题思路 这个问题可以通过动态规划(DP)来解决。我们需要维护两个DP数组: 1. `minSwaps[i]` 表示以 `arr[i]` 结尾的严格递增序列所需的最小交换次数。 2. `prevIndex[i]` 表示在形成以 `arr[i]` 结尾的严格递增序列时,`arr[i]` 应该从哪个位置的前一个位置交换过来(即 `arr[i]` 应该放在哪个位置以形成递增序列)。 ### PHP 示例代码 ```php function minSwapsToSort(array $arr): int { $n = count($arr); $minSwaps = array_fill(0, $n, PHP_INT_MAX); $prevIndex = array_fill(0, $n, -1); $minSwaps[0] = 0; for ($i = 1; $i < $n; $i++) { // 不交换,继承前一个位置的最小交换次数 $minSwaps[$i] = $minSwaps[$i - 1] + ($arr[$i] <= $arr[$i - 1] ? 1 : 0); $prevIndex[$i] = $i - 1; // 尝试从之前的某个位置交换过来,找到最优解 for ($j = 0; $j < $i; $j++) { if ($arr[$j] <= $arr[$i]) { if ($minSwaps[$j] + ($i - $j - ($arr[$j] <= $arr[$prevIndex[$j]] ? 1 : 0)) < $minSwaps[$i]) { $minSwaps[$i] = $minSwaps[$j] + ($i - $j - ($arr[$j] <= $arr[$prevIndex[$j]] ? 1 : 0)); $prevIndex[$i] = $j; } } } } // 检查是否存在无法递增的情况 if ($minSwaps[$n - 1] == PHP_INT_MAX) { return -1; } return $minSwaps[$n - 1]; } // 测试 $arr = [3, 2, 3, 1]; echo minSwapsToSort($arr); // 输出 2 ``` ### 注意 - PHP 示例中,`PHP_INT_MAX` 用于初始化 `minSwaps` 数组,表示初始时假设无法通过交换得到递增序列。 - 这个问题的时间复杂度较高,因为它涉及到两层循环,内层循环需要遍历到当前位置之前的所有位置。对于大数据集,可能需要考虑优化或使用其他算法。 - 码小课网站中有更多关于算法和数据结构的分享,欢迎访问学习。
推荐面试题