难度中等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来说,差分数组定义为:
进而,可以推导出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;
}
};
难度困难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 <= A.length <= 30000
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;
}
};