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


题目描述补充

题目:给定一个整数数组 arr,你可以交换任意两个相邻元素一次。请编写一个算法,找出使数组元素严格递增所需的最小交换次数。如果无法通过交换使得数组严格递增,则返回 -1

示例

  • 输入:arr = [3, 2, 3, 1]
  • 输出:2
  • 解释:我们可以进行两次交换,先将 32 交换,得到 [2, 3, 3, 1],再将 31 交换,得到 [2, 1, 3, 3],此时数组是严格递增的。

解题思路

这个问题可以通过动态规划(DP)来解决。我们需要维护两个DP数组:

  1. minSwaps[i] 表示以 arr[i] 结尾的严格递增序列所需的最小交换次数。
  2. prevIndex[i] 表示在形成以 arr[i] 结尾的严格递增序列时,arr[i] 应该从哪个位置的前一个位置交换过来(即 arr[i] 应该放在哪个位置以形成递增序列)。

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 数组,表示初始时假设无法通过交换得到递增序列。
  • 这个问题的时间复杂度较高,因为它涉及到两层循环,内层循环需要遍历到当前位置之前的所有位置。对于大数据集,可能需要考虑优化或使用其他算法。
  • 码小课网站中有更多关于算法和数据结构的分享,欢迎访问学习。
推荐面试题