- 各类区间和
- 数组不变,求区间和:— 前缀和、树状数组、线段树
- 多次修改某个点,求区间和:— 树状数组、线段树
- 多次修改某个区间,输出最终结果:— 差分
- 多次修改某个区间,求区间和: — 线段树、树状数组(看修改区间范围大小)
- 多次将某个区间变成同一个数,求区间和: — 线段树、树状数组(看修改区间范围大小)
线段树:代码很长,常数很大,实际表现不算很好。最后考虑。
1. 题型1:坐标转换
// 地震预警通知
坐标<row, col>,
地图长度:mapSideLen,是gridSideLen的整数倍
栅格长度:gridSideLen, 保证是奇数
n : mapSideLen / gridSideLen
属于的区间:
int r = (row / gridSideLen);
int c = (col / gridSideLen);
int seq = r * n + c + 1; // 栅格序号
栅格的中心位置:
int midRow = ((seq - 1) / n) * gridSideLen + gridSideLen / 2;
int midCol = ((seq - 1) % n) * gridSideLen + gridSideLen / 2;
曼哈顿距离:
int d = abs(midRow - posRow) + abs(midCol - posCol);
存储的数据结构:
unordered_map<int, vector<int>> mp;
// 序号, 距离,用户数
vector<int> one = {seq, d, userNum}
2. 题型2:摩尔投票法
- 概念: 又称多数投票法,主要用于解决一个数组中的众数的问题。(核心:对抗消耗)
- 证明:
- 如果候选人不是maj 则 maj,会和其他非候选人一起反对 会反对候选人,所以候选人一定会下台(maj==0时发生换届选举)
- 如果候选人是maj , 则maj 会支持自己,其他候选人会反对,同样因为maj 票数超过一半,所以maj 一定会成功当选
- 步骤:
- 对抗阶段:分属两个候选人的票数两两对抗抵消
- 计数阶段:计算对抗结果中最后留下的候选人票数是否有效
```cpp
// 主要元素 https://leetcode-cn.com/problems/find-majority-element-lcci/
// 数组中占比超过一半的元素称之为主要元素。
// 给定一个整数数组,找到它的主要元素。
// 若没有,返回-1。
int majorityElement(vector
& nums) { int candidate = -1; int count = 0; // 对抗阶段 for (int& num : nums) { if (count == 0) {
} count += (num == candidate) ? 1 : -1; } count = 0; int length = nums.size(); for (int& num : nums) { if (num == candidate) {candidate = num;
} } return count * 2 > length ? candidate : -1; }count++;
```cpp
// 多数元素 https://leetcode-cn.com/problems/majority-element/
// 给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。
// 你可以假设数组是非空的,并且给定的数组总是存在多数元素。
// 法1:哈希计数,时间复杂度O(n),空间复杂度O(n);
int majorityElement(vector<int>& nums) {
unordered_map<int, int> counts;
int majority = 0, cnt = 0;
for (int num: nums) {
++counts[num];
if (counts[num] > cnt) {
majority = num;
cnt = counts[num];
}
}
return majority;
}
// 法2:排序, 返回n/2位置的数,时间复杂度O(nlogn), O(1)
// 空间复杂度:O(logn)。如果使用语言自带的排序算法,需要使用O(logn) 的栈空间。
// 如果自己编写堆排序,则只需要使用 O(1)O(1) 的额外空间。
int majorityElement(vector<int>& nums) {
sort(nums.begin(), nums.end());
return nums[nums.size() / 2];
}
// 法3:摩尔投票法:时间复杂度O(n), 空间复杂度O(1)
int majorityElement(vector<int>& nums) {
int candidate = -1;
int count = 0;
for (int& num : nums) {
if (count == 0) {
candidate = num;
}
count += (num == candidate) ? 1 : -1;
}
return candidate;
}
// 求众数II https://leetcode-cn.com/problems/majority-element-ii/
// 给定一个大小为 n 的整数数组,找出其中所有出现超过 ⌊ n/3 ⌋ 次的元素。
// 反证法可以得到,这数最多有两个。
class Solution {
public:
vector<int> majorityElement(vector<int>& nums) {
vector<int> ans;
int element1 = 0;
int element2 = 0;
int vote1 = 0;
int vote2 = 0;
for (auto & num : nums) {
if (vote1 > 0 && num == element1) { //如果该元素为第一个元素,则计数加1
vote1++;
} else if (vote2 > 0 && num == element2) { //如果该元素为第二个元素,则计数加1
vote2++;
} else if (vote1 == 0) { // 选择第一个元素
element1 = num;
vote1++;
} else if (vote2 == 0) { // 选择第二个元素
element2 = num;
vote2++;
} else { //如果三个元素均不相同,则相互抵消1次
vote1--;
vote2--;
}
}
int cnt1 = 0;
int cnt2 = 0;
for (auto & num : nums) {
if (vote1 > 0 && num == element1) {
cnt1++;
}
if (vote2 > 0 && num == element2) {
cnt2++;
}
}
// 检测元素出现的次数是否满足要求
if (vote1 > 0 && cnt1 > nums.size() / 3) {
ans.push_back(element1);
}
if (vote2 > 0 && cnt2 > nums.size() / 3) {
ans.push_back(element2);
}
return ans;
}
};