差分数组(解决区间+a问题)

这篇博客讨论了如何使用差分数组来解决计算生存人数最多年份的问题,以及在K连续位翻转次数问题中的应用。通过差分数组,可以高效地更新区间内的数据,简化问题的复杂度。文章通过实例解释了差分数组的概念,并展示了如何利用其性质进行快速操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

面试题 16.10. 生存人数

难度中等27

给定 N 个人的出生年份和死亡年份,第 i 个人的出生年份为 birth[i],死亡年份为 death[i],实现一个方法以计算生存人数最多的年份。

你可以假设所有人都出生于 1900 年至 2000 年(含 1900 和 2000 )之间。如果一个人在某一年的任意时期处于生存状态,那么他应该被纳入那一年的统计中。例如,生于 1908 年、死于 1909 年的人应当被列入 1908 年和 1909 年的计数。

如果有多个年份生存人数相同且均为最大值,输出其中最小的年份。

示例:

输入:
birth = {1900, 1901, 1950}
death = {1948, 1951, 2000}
输出: 1901

提示:

  • 0 < birth.length == death.length <= 10000
  • birth[i] <= death[i]

题解: 这里显然的想法是构建一个生存人数的的数组,存储不同年份的生存人数,取最大值。存储的方式首先会想到遍历birth和death数组,对每个区间的年份对其进行全加1,这一方法显然可行,然而由于每个区间都需要对区间内所有年份+1,时间复杂度较高。

一种显著提高性能的方法是采用差分数组,对于存储生存人数的数组data来说,差分数组定义为:

diff = \begin{Bmatrix} data[i] - data[i - 1], i > 0\\ 0, i =0 \end{Bmatrix}

进而,可以推导出data[n]  = diff[0] + diff[1] + ... + diff[n],可以发现差分数组跟前缀和相对应。

有了差分数组后,可以发现,对于data区间 [i , j] 的数值同时+a,差分数组仅需要在diff[i] + a, diff[j + 1] - a两步操作即可。

因此通过简单的遍历birth和death来维护一个差分数组即可代表我们想要的存储生存人数data数组。

class Solution {
public:
	int maxAliveYear(vector<int>& birth, vector<int>& death) {
		int diff[102] = { 0 };
		for (int i = 0; i < birth.size(); ++i) {
			diff[birth[i] - 1900]++;
			diff[death[i] + 1 - 1900]--;
		}
		int res = 0, year = 0, Sum = 0;
		for (int i = 0; i < 102; ++i) {
			Sum += diff[i];
			if (Sum > res) {
				res = Sum;
				year = i;
			}
		}
		return year + 1900;
	}
};

995. K 连续位的最小翻转次数

难度困难190

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

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

示例 1:

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

示例 2:

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

示例 3:

输入:A = [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. 1 <= A.length <= 30000
  2. 1 <= K <= A.length

题解:这道题与上题类似,同样是区间+a的问题,采用差分数组,对于该题来说,还需要判断某个点的值在累加的翻转次数后是否仍需翻转。

class Solution {
public:
    int minKBitFlips(vector<int>& A, int K) {
        vector<int> diff(A.size() + 1);
        diff[0] = 0;
        int Sum = 0, res = 0;
        for(int i = 0;i < A.size(); ++i){
            Sum += diff[i];
            if((Sum & 1) ^ A[i] == 0){
                if(i + K > A.size())
                    return -1;
                diff[i + K] --;
                Sum++;
                res++;
            }
        }
        return res;
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值