Skip to content

Files

Latest commit

7840036 · Jul 24, 2024

History

History
This branch is 1 commit ahead of, 477 commits behind doocs/leetcode:main.

0995.Minimum Number of K Consecutive Bit Flips

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
Jul 24, 2024
Jul 24, 2024
Jun 25, 2024
Jun 25, 2024
Jun 25, 2024
Jun 25, 2024
Jun 25, 2024
Nov 30, 2023
Jun 25, 2024
Jun 25, 2024
Jun 25, 2024
Jun 25, 2024
Jun 25, 2024
Jun 25, 2024
comments difficulty edit_url tags
true
困难
位运算
队列
数组
前缀和
滑动窗口

English Version

题目描述

给定一个二进制数组 nums 和一个整数 k

k位翻转 就是从 nums 中选择一个长度为 k子数组 ,同时把子数组中的每一个 0 都改成 1 ,把子数组中的每一个 1 都改成 0

返回数组中不存在 0 所需的最小 k位翻转 次数。如果不可能,则返回 -1 。

子数组 是数组的 连续 部分。

 

示例 1:

输入:nums = [0,1,0], K = 1
输出:2
解释:先翻转 A[0],然后翻转 A[2]。

示例 2:

输入:nums = [1,1,0], K = 2
输出:-1
解释:无论我们怎样翻转大小为 2 的子数组,我们都不能使数组变为 [1,1,1]。

示例 3:

输入:nums = [0,0,0,1,0,1,1,0], K = 3
输出:3
解释:
翻转 A[0],A[1],A[2]: A变成 [1,1,1,1,0,1,1,0]
翻转 A[4],A[5],A[6]: A变成 [1,1,1,1,1,0,0,0]
翻转 A[5],A[6],A[7]: A变成 [1,1,1,1,1,1,1,1]

 

提示:

  • 1 <= nums.length <= 105
  • 1 <= k <= nums.length

解法

方法一:差分数组

我们注意到,对于若干个连续的元素进行反转,其结果与对这些元素进行反转的次序无关。因此我们可以贪心地考虑每个位置需要进行反转的次数。

我们不妨从左到右处理数组。

假设当前我们需要处理位置 i ,而位置 i 左侧的元素已经被处理完毕,如果 i 位置的元素为 0 ,那么我们必须进行反转操作,我们需要将 [ i , . . i + k 1 ] 区间内的元素进行反转。这里我们用一个差分数组 d 来维护每个位置的反转次数,那么判断当前位置 i 是否需要反转,只需要看 s = j = 0 i d [ j ] 以及 n u m s [ i ] 的奇偶性,如果 s n u m s [ i ] 奇偶性相同,那么位置 i 的元素仍然为 0 ,需要进行反转。此时我们判断一下 i + k 是否超出了数组的长度,如果超出了数组的长度,那么就无法完成目标,返回 1 。否则我们令 d [ i ] 增加 1 ,同时令 d [ i + k ] 减少 1 ,然后将答案增加 1 ,并且 s 增加 1

这样当我们处理完数组中的所有元素时,返回答案即可。

时间复杂度 O ( n ) ,空间复杂度 O ( n ) 。这里 n 是数组 n u m s 的长度。

Python3

class Solution:
    def minKBitFlips(self, nums: List[int], k: int) -> int:
        n = len(nums)
        d = [0] * (n + 1)
        ans = s = 0
        for i, x in enumerate(nums):
            s += d[i]
            if s % 2 == x:
                if i + k > n:
                    return -1
                d[i] += 1
                d[i + k] -= 1
                s += 1
                ans += 1
        return ans

Java

class Solution {
    public int minKBitFlips(int[] nums, int k) {
        int n = nums.length;
        int[] d = new int[n + 1];
        int ans = 0, s = 0;
        for (int i = 0; i < n; ++i) {
            s += d[i];
            if (s % 2 == nums[i]) {
                if (i + k > n) {
                    return -1;
                }
                ++d[i];
                --d[i + k];
                ++s;
                ++ans;
            }
        }
        return ans;
    }
}

C++

class Solution {
public:
    int minKBitFlips(vector<int>& nums, int k) {
        int n = nums.size();
        int d[n + 1];
        memset(d, 0, sizeof(d));
        int ans = 0, s = 0;
        for (int i = 0; i < n; ++i) {
            s += d[i];
            if (s % 2 == nums[i]) {
                if (i + k > n) {
                    return -1;
                }
                ++d[i];
                --d[i + k];
                ++s;
                ++ans;
            }
        }
        return ans;
    }
};

Go

func minKBitFlips(nums []int, k int) (ans int) {
	n := len(nums)
	d := make([]int, n+1)
	s := 0
	for i, x := range nums {
		s += d[i]
		if s%2 == x {
			if i+k > n {
				return -1
			}
			d[i]++
			d[i+k]--
			s++
			ans++
		}
	}
	return
}

TypeScript

function minKBitFlips(nums: number[], k: number): number {
    const n = nums.length;
    const d: number[] = Array(n + 1).fill(0);
    let [ans, s] = [0, 0];
    for (let i = 0; i < n; ++i) {
        s += d[i];
        if (s % 2 === nums[i]) {
            if (i + k > n) {
                return -1;
            }
            d[i]++;
            d[i + k]--;
            s++;
            ans++;
        }
    }
    return ans;
}

Rust

impl Solution {
    pub fn min_k_bit_flips(nums: Vec<i32>, k: i32) -> i32 {
        let n = nums.len();
        let mut d = vec![0; n + 1];
        let mut ans = 0;
        let mut s = 0;
        for i in 0..n {
            s += d[i];
            if s % 2 == nums[i] {
                if i + (k as usize) > n {
                    return -1;
                }
                d[i] += 1;
                d[i + (k as usize)] -= 1;
                s += 1;
                ans += 1;
            }
        }
        ans
    }
}

方法二:滑动窗口

我们可以用一个变量 flipped 来表示当前位置是否翻转,如果 flipped 1 ,表示当前位置已经翻转,否则表示当前位置未翻转。对于翻转过的位置,我们可以将其值设置为 1 ,这样我们就可以区分出哪些位置已经翻转过了。

接下来我们从左到右遍历数组,对于每个位置 i ,如果 i k i k 位置的元素为 1 ,那么当前位置的翻转状态应该与前一个位置的翻转状态相反。即 flipped = flipped 1 。如果当前位置的元素与当前位置的翻转状态相同,那么我们需要翻转当前位置,此时我们判断一下 i + k 是否超出了数组的长度,如果超出了数组的长度,那么就无法完成目标,返回 1 。否则我们将当前位置的翻转状态取反,同时将答案增加 1 ,并且将当前位置的元素设置为 1

这样当我们处理完数组中的所有元素时,返回答案即可。

时间复杂度 O ( n ) ,其中 n 是数组 n u m s 的长度。空间复杂度 O ( 1 )

Python3

class Solution:
    def minKBitFlips(self, nums: List[int], k: int) -> int:
        ans = flipped = 0
        for i, x in enumerate(nums):
            if i >= k and nums[i - k] == -1:
                flipped ^= 1
            if x == flipped:
                if i + k > len(nums):
                    return -1
                flipped ^= 1
                ans += 1
                nums[i] = -1
        return ans

Java

class Solution {
    public int minKBitFlips(int[] nums, int k) {
        int n = nums.length;
        int ans = 0, flipped = 0;
        for (int i = 0; i < n; ++i) {
            if (i >= k && nums[i - k] == -1) {
                flipped ^= 1;
            }
            if (flipped == nums[i]) {
                if (i + k > n) {
                    return -1;
                }
                flipped ^= 1;
                ++ans;
                nums[i] = -1;
            }
        }
        return ans;
    }
}

C++

class Solution {
public:
    int minKBitFlips(vector<int>& nums, int k) {
        int n = nums.size();
        int ans = 0, flipped = 0;
        for (int i = 0; i < n; ++i) {
            if (i >= k && nums[i - k] == -1) {
                flipped ^= 1;
            }
            if (flipped == nums[i]) {
                if (i + k > n) {
                    return -1;
                }
                flipped ^= 1;
                ++ans;
                nums[i] = -1;
            }
        }
        return ans;
    }
};

Go

func minKBitFlips(nums []int, k int) (ans int) {
	flipped := 0
	for i, x := range nums {
		if i >= k && nums[i-k] == -1 {
			flipped ^= 1
		}
		if flipped == x {
			if i+k > len(nums) {
				return -1
			}
			flipped ^= 1
			ans++
			nums[i] = -1
		}
	}
	return
}

TypeScript

function minKBitFlips(nums: number[], k: number): number {
    const n = nums.length;
    let [ans, flipped] = [0, 0];
    for (let i = 0; i < n; i++) {
        if (nums[i - k] === -1) {
            flipped ^= 1;
        }
        if (nums[i] === flipped) {
            if (i + k > n) {
                return -1;
            }
            flipped ^= 1;
            ++ans;
            nums[i] = -1;
        }
    }
    return ans;
}

Rust

impl Solution {
    pub fn min_k_bit_flips(mut nums: Vec<i32>, k: i32) -> i32 {
        let mut ans = 0;
        let mut flipped = 0;
        let k = k as usize;

        for i in 0..nums.len() {
            if i >= k && nums[i - k] == -1 {
                flipped ^= 1;
            }
            if flipped == nums[i] {
                if i + k > nums.len() {
                    return -1;
                }
                flipped ^= 1;
                ans += 1;
                nums[i] = -1;
            }
        }

        ans
    }
}