leetcode 995. K 连续位的最小翻转次数(差分)

在仅包含 0 和 1 的数组 A 中,一次 K 位翻转包括选择一个长度为 K 的(连续)子数组,同时将子数组中的每个 0 更改为 1,而每个 1 更改为 0。

返回所需的 K 位翻转的最小次数,以便数组没有值为 0 的元素。如果不可能,返回 -1。

假hard真medium。这种题一定是从一边开始处理,逐步翻转。因为如果有解的话,翻转次数是一定的。所有的翻转区间一定是由一个或者多个有重叠的翻转区间(成为联通区间)组成。比如[1, 4]、[3, 6]和[5, 8]构成了一个联通区间[1, 8]。这个问题实际上可以拆分为处理这些联通区间。可以知道如果有解的话,联通区间的左右端点一定只被翻转了一次(翻转奇数次相当于翻转一次,翻转偶数次相当于没有翻转)。那么可以从左端点出发,对于每个点,如果为1则跳过,为0则翻转以当前位置为左端点长度为k的区间。如果能处理完该联通区间的话则有解。

对于这个题,有以上结论的话实际上直接遍历1到i + k - 1,当前为1跳过,为0则翻转。朴素地翻转显然会t,这里可以用差分的思想对区间进行翻转,在遍历的时候求前缀和得到当前点的翻转次数,偶数次忽略,奇数次则用a[i] = a[i] ^ 1来更新a[i],再进行判断。注意由于遍历范围并非1到n,因此最后一部分的a[i]需要单独更新。

class Solution {
public:
    int n, k, a[30005], diff[30005];
    void add(int x, int y)
    {
    	diff[x]++;
	    diff[y + 1]--;
    }
    int minKBitFlips(vector<int>& A, int K) {
        k = K, n = A.size();
        for(int i = 0; i < A.size(); i++) a[i + 1] = A[i];
        int ans = 0;
	    for(int i = 1; i + k - 1 <= n; i++)
	    {
		    diff[i] += diff[i - 1];
		    if(diff[i] & 1) a[i] ^= 1;
		    if(a[i] == 1) continue;
		    else
		    {
		    	add(i, i + k - 1);
		    	ans++;
		    	a[i] = 1;
		    }
	    }
	    for(int i = n - k + 2; i <= n; i++)
	    {
	    	diff[i] += diff[i - 1];
	    	if(diff[i] & 1) a[i] ^= 1;
	    }
        for(int i = 1; i <= n; i++) if(a[i] == 0) return -1;
        return ans;
    }
};
posted @   脂环  阅读(81)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
历史上的今天:
2020-02-18 Codeforces Round #621 (Div. 1 + Div. 2) C. Cow and Message
2020-02-18 洛谷P2330 [SCOI2005]繁忙的都市
2020-02-18 HDU2612 Find a way (跑两遍BFS)
点击右上角即可分享
微信分享提示
主题色彩