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;
}
};
分类:
算法基础—前缀和/差分
, 题库—Leetcode
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 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)