hash法
其实可以简单的理解map和arr差不多,不过map的索引值不局限为整数
当我们想使用哈希法来解决问题的时候,我们一般会选择如下三种数据结构。
- 数组
- set (集合)
- map(映射)
虽然std::set、std::multiset 的底层实现是红黑树,不是哈希表,std::set、std::multiset 使用红黑树来索引和存储,不过给我们的使用方式,还是哈希法的使用方式,即key和value。所以使用这些数据结构来解决映射问题的方法,我们依然称之为哈希法。 map也是一样的道理。
哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费,反之使用数组, 不过算法竞赛哪个方便用哪个就行了
两个数组的交集
用set最好,不用我习惯map了
常见类型的字节长度
快乐数
两数之和
四数相加
提前预处理的思想还是挺妙的
arr中的快排
vector中的快排写法
sort(nums.begin(), nums.end());
向二维vector里面添加一维元素
xxxx.push_back(vector<int>{nums[i], nums[left], nums[right]}
*三数之和
这题的关键是去重
去重有两种思路吧
1 是在遍历的时候把重复的给去掉
2 是在最后统计结果的时候判断结构集里面有没有重复的
目前来看前者更容易写
极易错的点:while()里面要是有边界判断啥的,一定要写,并且一定要放在其他条件的前面
要是放在后面,另一个条件是arr[]的,就很容易数据越界!!!
这道题hash不好去重,双指针的思路很巧
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> result;
sort(nums.begin(), nums.end());
// 找出a + b + c = 0
// a = nums[i], b = nums[left], c = nums[right]
for (int i = 0; i < nums.size(); i++) {
// 排序之后如果第一个元素已经大于零,那么无论如何组合都不可能凑成三元组,直接返回结果就可以了
if (nums[i] > 0) {
return result;
}
// 错误去重a方法,将会漏掉-1,-1,2 这种情况
/*
if (nums[i] == nums[i + 1]) {
continue;
}
*/
// 正确去重a方法
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
int left = i + 1;
int right = nums.size() - 1;
while (right > left) {
// 去重复逻辑如果放在这里,0,0,0 的情况,可能直接导致 right<=left 了,从而漏掉了 0,0,0 这种三元组
/*
while (right > left && nums[right] == nums[right - 1]) right--;
while (right > left && nums[left] == nums[left + 1]) left++;
*/
if (nums[i] + nums[left] + nums[right] > 0) right--;
else if (nums[i] + nums[left] + nums[right] < 0) left++;
else {
result.push_back(vector<int>{nums[i], nums[left], nums[right]});
// 去重逻辑应该放在找到一个三元组之后,再对b 和 c去重
while (right > left && nums[right] == nums[right - 1]) right--;
while (right > left && nums[left] == nums[left + 1]) left++;
// 找到答案时,双指针同时收缩
right--;
left++;
}
}
}
return result;
}
};
四数之和II
有一个很重要的细节是,它和三树之和不一样,target 不一定为非负数,所以那两个剪枝要加个条件
如: [1,-2,-5,-4,-3,3,3,5] -11
小总结
此文章用于笔者记录学习,也希望对你有帮助