复习用tip
1、哈希表需要注意效率,能用数组的时候还是要用数组的。map的用法参考
2、去重的技巧
454.四数相加II
题目链接
两两一组(各n^2),寻找排列组合数。注意不是要求把每个下标求出来,只要知道数目即可
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
int n=nums1.size();
//nums1[i]+nums2[j]+nums3[k]+nums4[l]=0
//a+b+c+d=0
int count{0};//组合数
unordered_map<int,int>mp;//a+b,出现次数
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
mp[-(nums1[i]+nums2[j])]++;
}
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
auto iter=mp.find(nums3[i]+nums4[j]);
if(iter!=mp.end()){
count+=iter->second;
}
}
}
return count;
}
383. 赎金信
题目链接
用map空间复杂度太大,题目给出只有小写字母,可以用数组
map:
bool canConstruct(string need, string give) {
//give>=need
unordered_map<char,int>mp;//
for(char c:give){//统计提供的字符
mp[c]++;
}
for(char c:need){
auto iter=mp.find(c);
if(iter!=mp.end()){//如果存在
mp[c]--;
if(mp[c]<0)
return false;//如果不够
}else{//如果不存在
return false;
}
}
return true;
}
数组:
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
int record[26] = {0};
//add
if (ransomNote.size() > magazine.size()) {
return false;
}
for (int i = 0; i < magazine.length(); i++) {
// 通过record数据记录 magazine里各个字符出现次数
record[magazine[i]-'a'] ++;
}
for (int j = 0; j < ransomNote.length(); j++) {
// 遍历ransomNote,在record里对应的字符个数做--操作
record[ransomNote[j]-'a']--;
// 如果小于零说明ransomNote里出现的字符,magazine没有
if(record[ransomNote[j]-'a'] < 0) {
return false;
}
}
return true;
}
};
15. 三数之和
vector<vector<int>> threeSum(vector<int>& nums) {
//a=nums[i],b=nums[j],c=nums[k]
//思路1:哈希法,统计a+b的所有结果,再找c------>太麻烦
//思路2:双指针法:先排序,先确定a,再从右边找b和c
vector<vector<int>>ans;
sort(nums.begin(),nums.end());
if(nums[0]>0)
return ans;
int n=nums.size();
for(int i=0;i<n;i++){//a
int a=nums[i];
if(nums[i]>0)
return ans;
if(i>0&&nums[i]==nums[i-1]) //对a去重
continue;
int left=i+1;
int right=n-1;
while(left<right){//b,c
int b=nums[left],c=nums[right];
if(a+b+c<0) left++;
else if(a+b+c>0)right--;
else{
ans.push_back(vector<int>{a,b,c});
// 去重逻辑应该放在找到一个三元组之后,对b和c去重
while (right > left && nums[left] == nums[left + 1]) left++;//b
while (right > left && nums[right] == nums[right - 1]) right--;//c
left++;right--;
}
}
}
return ans;
}
18. 四数之和
vector<vector<int>> fourSum(vector<int>& nums, int target) {
// d=nums[k],a=nums[i],b=nums[left],c=nums[right]
// 在三数之和的基础上多一层for循环---->d
vector<vector<int>> ans;
sort(nums.begin(), nums.end());
int n = nums.size();
for (int k = 0; k < n; k++) { // d
int d = nums[k];
if (d > target && d > 0)//要考虑负数的情况
break;
//return ans;//不可以用return
if (k > 0 && nums[k] == nums[k - 1]) // 对d去重
continue;
for (int i = k+1; i < n; i++) { // a
int a = nums[i];
if ((d+a) > target && (a+d) > 0) //可以优化为:if ((d+a) > target && a > 0)
break; //不可以用return
if (i > k+1 && nums[i] == nums[i - 1]) // 对a去重
continue;
int left = i + 1;
int right = n - 1;
while (left < right) { // b,c
int b = nums[left], c = nums[right];
if ((long)a + b + c + d < target)//会溢出
left++;
else if ((long)a + b + c + d > target)
right--;
else {
ans.push_back(vector<int>{a, b, c, d});
// 去重逻辑应该放在找到一个三元组之后,对b和c去重
while (right > left && nums[left] == nums[left + 1])
left++; // b
while (right > left && nums[right] == nums[right - 1])
right--; // c
left++;
right--;
}
}
}
}
return ans;
}