[每日一题] leetcode 801. 使序列递增的最小交换次数

113 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第12天,点击查看活动详情

801. 使序列递增的最小交换次数

我们有两个长度相等且不为空的整型数组 nums1 和 nums2 。在一次操作中,我们可以交换 nums1[i] 和 nums2[i]的元素。

例如,如果 nums1 = [1,2,3,8] , nums2 =[5,6,7,4] ,你可以交换 i = 3 处的元素,得到 nums1 =[1,2,3,4] 和 nums2 =[5,6,7,8] 。

返回 使 nums1 和 nums2 严格递增 所需操作的最小次数 。

数组 arr 严格递增 且  arr[0] < arr[1] < arr[2] < ... < arr[arr.length - 1] 。

思路

要求最小的交换次数

首先,我们若是枚举所有操作,一共有多少种操作呢?

设长度为n对于每次交换以后,不计算是否合法的情况下:每次操作有2种结果答案为:2×2×2×2...×2=2n我们总的操作次数是2n个操作次数设 长度 为n 对于每次交换以后,不计算是否合法的情况下:\\ 每次操作有2种结果 \\ 答案为:2 \times 2 \times 2 \times 2 ... \times 2 = 2^n \\ 我们总的操作次数是 2^n个操作次数

然后,我们可以先考虑使用dfs去枚举这2n2^n个状态,就可以得到最少的答案了

但是,我们的复杂度太高了 21052^{10^5} 是一个天文数字!

绝对不可能在一秒钟之内运算完(也许未来可以?

我们得考虑一下优化问题

优化,我们观察一下数组的前后两项之间的关系呢?

现在设第一个数组为a,第二个数组为b,现在观察第i项和第i1项元素那么,交换情况一共有四种:case{a[i]=>a[i+1], b[i]=>b[i+1]a[i]=>b[i+1], b[i]=>a[i+1]b[i]=>a[i+1], a[i]=>b[i+1]b[i]=>b[i+1], a[i]=>a[i+1]我们分别用0,和1来代表是否被交换的话,可以表示为:case{0,00,11,01,1现在设第一个数组为 a,第二个数组为b,现在观察第i项和第i-1项元素 \\ 那么,交换情况一共有四种:\\ case \begin{cases} a[i] => a[i+1], \ b[i] => b[i+1] \\ a[i] => b[i+1], \ b[i] => a[i+1] \\ b[i] => a[i+1], \ a[i] => b[i+1] \\ b[i] => b[i+1], \ a[i] => a[i+1] \end{cases} \\ 我们分别用 0,和1来代表 是否被交换的话,可以表示为: case \begin{cases} 0, 0 \\ 0, 1 \\ 1, 0 \\ 1, 1 \\ \end{cases} \\

那么,无论第i1前面的项如何变幻,其实都和第i项无关,关系在于第i1那么,无论第i-1前面的项如何变幻,其实都和第i项无关,关系在于第i-1项

所以,我们就可以对于每一项,去枚举它上面一项所变化的策略,并以此来枚举本项交换的策略

每次枚举共4种情况

所以,整体时间复杂度即为 O(n4)O(n * 4)

递推方程式为:

对于每一种情况,满足条件时进行如下转移:case{dp[i][0]=min(dp[i][0],dp[i1][0])dp[i][0]=min(dp[i][0],dp[i1][1])dp[i][1]=min(dp[i][1],dp[i1][0]+1)dp[i][1]=min(dp[i][1],dp[i1][1]+1)对于每一种情况,满足条件时进行如下转移:\\ case \begin{cases} dp[i][0] = min(dp[i][0], dp[i - 1][0]) \\ dp[i][0] = min(dp[i][0], dp[i - 1][1]) \\ dp[i][1] = min(dp[i][1], dp[i - 1][0] + 1) \\ dp[i][1] = min(dp[i][1], dp[i - 1][1] + 1) \\ \end{cases}

代码

use std::cmp::{max, min};
use std::mem::swap;
impl Solution {
    pub fn min_swap(nums1: Vec<i32>, nums2: Vec<i32>) -> i32 {
        let n = nums1.len();
        const INF: i32 = 0x3f3f3f3f;
        let mut dp: Vec<[i32; 2]> = vec![];
        dp.resize(n, [INF, INF]);
        dp[0][0] = 0;
        dp[0][1] = 1;
        for i in 1..n {
            let (mut a, mut b, mut x, mut y) = 
            (nums1[i], nums2[i], nums1[i - 1], nums2[i - 1]);
            for j in 0..2 as usize {
                for k in 0..2 as usize {
                    if x < a && y < b {
                        dp[i][j] = min(dp[i][j], dp[i - 1][k] + j as i32);
                    }
                    swap(&mut x, &mut y);
                }
                swap(&mut a, &mut b);
            }
        }
        return min(dp[n - 1][0], dp[n - 1][1]);
    }
}