列表

详情


1703. 得到连续 K 个 1 的最少相邻交换次数

给你一个整数数组 nums 和一个整数 k 。 nums 仅包含 0 和 1 。每一次移动,你可以选择 相邻 两个数字并将它们交换。

请你返回使 nums 中包含 k 个 连续 1 的 最少 交换次数。

 

示例 1:

输入:nums = [1,0,0,1,0,1], k = 2
输出:1
解释:在第一次操作时,nums 可以变成 [1,0,0,0,1,1] 得到连续两个 1 。

示例 2:

输入:nums = [1,0,0,0,0,0,1,1], k = 3
输出:5
解释:通过 5 次操作,最左边的 1 可以移到右边直到 nums 变为 [0,0,0,0,0,1,1,1] 。

示例 3:

输入:nums = [1,1,0,1], k = 2
输出:0
解释:nums 已经有连续 2 个 1 了。

 

提示:

原站题解

去查看

上次编辑到这里,代码来自缓存 点击恢复默认模板
class Solution { public: int minMoves(vector<int>& nums, int k) { } };

javascript 解法, 执行用时: 88 ms, 内存消耗: 63.8 MB, 提交时间: 2022-12-18 13:45:45

/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number}
 */
var minMoves = function(nums, k) {
    const g = [];
    const preSum = [];
    preSum.push(0);
    for (let i = 0; i < nums.length; i++) {
        if (nums[i] === 1) {
            g.push(i - g.length);
            preSum.push(preSum[preSum.length - 1] + g[g.length - 1]);
        }
    }
    let m = g.length, res = Number.MAX_VALUE;
    for (let i = 0; i <= m - k; i++) {
        let mid = i + Math.floor(k / 2);
        let r = g[mid];
        res = Math.min(res, (1 - k % 2) * r + (preSum[i + k] - preSum[mid + 1]) - (preSum[mid] - preSum[i]));
    }
    return res;
};

golang 解法, 执行用时: 108 ms, 内存消耗: 7.9 MB, 提交时间: 2022-12-18 13:45:27

func minMoves(nums []int, k int) int {
	n, m := len(nums), 0
	for i, p := range nums {
		if p != 0 {
			nums[m] = i - m
			m++
		}
	}
	if m == n { // 全部都是 1
		return 0
	}
	p := nums
	var sl, sm, sr int // s[i] s[i+k/2] s[i+k]
	for i, v := range p[:k] {
		if i < k/2 {
			sm += v
		}
		sr += v
	}
	ans := math.MaxInt
	for i, v := range p[:m-k+1] {
		ans = min(ans, sl+sr-sm*2-p[i+k/2]*(k%2))
		sl += v
		sm += p[i+k/2]
		sr += p[i+k]
	}
	return ans
}

func min(a, b int) int { if b < a { return b }; return a }

cpp 解法, 执行用时: 96 ms, 内存消耗: 107.4 MB, 提交时间: 2022-12-18 13:45:13

class Solution {
public:
    int minMoves(vector<int> &nums, int k) {
        int n = nums.size(), m = 0;
        for (int i = 0; i < n; ++i)
            if (nums[i]) {
                nums[m] = i - m;
                ++m;
            }
        if (m == n) return 0; // 全部都是 1
        auto &p = nums;
        int sl = 0; // s[i]
        int sm = accumulate(p.begin(), p.begin() + k / 2, 0); // s[i+k/2]
        int sr = accumulate(p.begin(), p.begin() + k, 0); // s[i+k]
        int ans = INT_MAX;
        for (int i = 0; i <= m - k; ++i) {
            ans = min(ans, sl + sr - sm * 2 - p[i + k / 2] * (k % 2));
            sl += p[i];
            sm += p[i + k / 2];
            sr += p[i + k];
        }
        return ans;
    }
};

java 解法, 执行用时: 4 ms, 内存消耗: 50.5 MB, 提交时间: 2022-12-18 13:44:58

class Solution {
    public int minMoves(int[] nums, int k) {
        int n = nums.length, m = 0;
        for (int i = 0; i < n; ++i)
            if (nums[i] != 0) {
                nums[m] = i - m;
                ++m;
            }
        if (m == n) return 0; // 全部都是 1
        int[] p = nums;
        int sl = 0, sm = 0, sr = 0; // s[i] s[i+k/2] s[i+k]
        for (int i = 0; i < k; ++i) {
            if (i < k / 2) sm += p[i];
            sr += p[i];
        }
        int ans = Integer.MAX_VALUE;
        for (int i = 0; i <= m - k; ++i) {
            ans = Math.min(ans, sl + sr - sm * 2 - p[i + k / 2] * (k % 2));
            sl += p[i];
            sm += p[i + k / 2];
            sr += p[i + k];
        }
        return ans;
    }
}

python3 解法, 执行用时: 244 ms, 内存消耗: 20.4 MB, 提交时间: 2022-12-18 13:44:43

class Solution:
    def minMoves(self, nums: List[int], k: int) -> int:
        m = 0
        for i, p in enumerate(i for i, x in enumerate(nums) if x):
            nums[i] = p - i
            m += 1
        if m == len(nums): return 0  # 全部都是 1
        ans, p = inf, nums
        sl, sm, sr = 0, sum(p[:k // 2]), sum(p[:k])  # s[i] s[i+k//2] s[i+k] 忽略切片开销
        for i in range(m - k + 1):
            ans = min(ans, sl + sr - sm * 2 - p[i + k // 2] * (k % 2))
            sl += p[i]
            sm += p[i + k // 2]
            sr += p[i + k]
        return ans

golang 解法, 执行用时: 108 ms, 内存消耗: 9.4 MB, 提交时间: 2022-12-18 13:44:21

func minMoves(nums []int, k int) int {
	p := []int{}
	for i, v := range nums {
		if v != 0 {
			p = append(p, i-len(p))
		}
	}
	m := len(p)
	s := make([]int, m+1) // p 的前缀和
	for i, v := range p {
		s[i+1] = s[i] + v
	}
	ans := math.MaxInt
	for i, v := range s[:m-k+1] { // p[i] 到 p[i+k-1] 中所有数到 p[i+k/2] 的距离之和,取最小值
		ans = min(ans, v+s[i+k]-s[i+k/2]*2-p[i+k/2]*(k%2))
	}
	return ans
}

func min(a, b int) int { if b < a { return b }; return a }

cpp 解法, 执行用时: 96 ms, 内存消耗: 115.3 MB, 提交时间: 2022-12-18 13:44:09

class Solution {
public:
    int minMoves(vector<int> &nums, int k) {
        vector<int> p;
        for (int i = 0; i < nums.size(); ++i)
            if (nums[i]) p.push_back(i - p.size());
        int m = p.size(), s[m + 1];
        s[0] = 0;
        partial_sum(p.begin(), p.end(), s + 1); // p 的前缀和
        int ans = INT_MAX;
        for (int i = 0; i <= m - k; ++i) // p[i] 到 p[i+k-1] 中所有数到 p[i+k/2] 的距离之和,取最小值
            ans = min(ans, s[i] + s[i + k] - s[i + k / 2] * 2 - p[i + k / 2] * (k % 2));
        return ans;
    }
};

java 解法, 执行用时: 10 ms, 内存消耗: 49.1 MB, 提交时间: 2022-12-18 13:43:57

class Solution {
    public int minMoves(int[] nums, int k) {
        var p = new ArrayList<Integer>();
        for (int i = 0; i < nums.length; ++i)
            if (nums[i] != 0) p.add(i - p.size());
        int m = p.size();
        int[] s = new int[m + 1]; // p 的前缀和
        for (int i = 0; i < m; i++)
            s[i + 1] = s[i] + p.get(i);
        int ans = Integer.MAX_VALUE;
        for (int i = 0; i <= m - k; ++i) // p[i] 到 p[i+k-1] 中所有数到 p[i+k/2] 的距离之和,取最小值
            ans = Math.min(ans, s[i] + s[i + k] - s[i + k / 2] * 2 - p.get(i + k / 2) * (k % 2));
        return ans;
    }
}

python3 解法, 执行用时: 204 ms, 内存消耗: 22.8 MB, 提交时间: 2022-12-18 13:43:42

# 中位数贪心
class Solution:
    def minMoves(self, nums: List[int], k: int) -> int:
        p = [q - i for i, q in enumerate(i for i, x in enumerate(nums) if x)]
        s = list(accumulate(p, initial=0))  # p 的前缀和
        return min(s[i] + s[i + k] - s[i + k // 2] * 2 - p[i + k // 2] * (k % 2)
                   for i in range(len(p) - k + 1))  # p[i:i+k] 中所有数到 p[i+k//2] 的距离之和,取最小值

上一题