[M差分] lcxx. 访问消失节点的最少时间(差分+贪心+读题+思维)
1. 题目来源
2. 题目解析
挺有意思的一道差分题目,来自与 2024年07月20日,lc 第135双周三的 Q3。全场大约 500 人做出来。算是一个比较难的 Q3 了,看起来大家对差分数组的知识理解和应用,还有所不足啊哈哈。
思路:
-
首先读题,题目有要求:
nums[i] <= k
,所以所有可能出现的X
都是在[0, k]
之间。 -
看数据范围,1e5 的时间范围,动态规划肯定也不行了,枚举 i,枚举 X 都是没啥前途的了。
-
那么思路就被限定在了:分类讨论、贪心。这类
O(n)
算法里面了。 -
看下我们的操作,假定
a=nums[i], b = nums[n - i - 1], d = |a-b|
,如果只修改一个数的话,可以获取到的最大取值范围即:m=max(a, k - a, b, k - b)
,也就是说: -
0<=X<d
时,只需要操作一次,即可让两数差值等于这个 X。 -
X=d
时,无需操作 -
d< x <= m
时,也只需要操作一次,即可让两数差值等于这个 X。 -
x > m
时,我们只能操作两次,才能让两数差值等于这个 X。
所以,可以遍历所有的数,求得 d,分别记录变成各个 X 的操作次数。
在上面的讨论,将 X 分段进行了讨论,我们需要将 [0, d)
这个区间段的所有 X 都需要 +1,因为都是等价的 X,所以比较自然的引入了 差分数组,给区间整体加上固定值。
最后,前缀和求和差分数组即可,每个下标都是 X 的需要的操作数。
挺不错的题目,需要一点分类讨论的思想,差分练习不错的题目。要时刻谨记:
- 差分操作是可以给一段区间加上一个固定的数。
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( 1 ) O(1) O(1)
class Solution {
public:
int minChanges(vector<int>& nums, int k) {
int n = nums.size();
int f[k + 2]; // 统计所有 X 的操作次数
memset(f, 0, sizeof(f));
// 枚举每个数对
for (int i = 0; i < n / 2; i ++ ) {
int a = nums[i], b = nums[n - i - 1];
int d = abs(a - b);
int m = max({a, k - a, b, k - b}); // 枚举数对最大的变化范围,在此一定有:m>=d
// 差分数组记录 落在各个区间 X 的操作数
// 0 <= X < d
f[0] ++ , f[d] --;
// d < X <= m
f[d + 1] ++ ,f[m + 1] -- ;
// x >= m
f[m + 1] += 2 ;
}
int res = n;
for (int i = 0, s = 0; i < k + 1; i ++ ) { // 差分求和,统计 X=i 需要的操作总数
s += f[i];
res = min(res, s);
}
return res;
}
};
原文地址:https://blog.csdn.net/yl_puyu/article/details/140580541
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!