第454题.四数相加II
对四个数组,从对称性上来看,应该两两处理,用两个for循环
与两数之和同理,这里只需让前两个数组之和,与后两个数组之和为相反数即可
需要用map记录前两个数组和的结果,与后两个数组的和去配对
注意这里配对成功之后不是count++,而是count+=前两个和出现的次数
因为前两个数组的和出现一次就代表一种排列组合
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
int count = 0;
unordered_map<int, int> map;
for(int n1:nums1)
for(int n2:nums2)
map[n1+n2]++;
for(int n3:nums3)
for(int n4:nums4)
{
if(map.find(-n3 - n4) != map.end())
{
// cout<<n3<<" "<<n4<<" "<<map.find(-n3 - n4)->first<<endl;
count += map.find(-n3 - n4)->second;
}
}
return count;
}
383. 赎金信
遇到字符串构成问题,需要统计字母出现次数的,首先用数组构建hash表
字符串问题,有序想双指针,无序想hash表或者先排序再处理
bool canConstruct(string ransomNote, string magazine) {
bool flag = true;
int arr[26] = {0};
for(char ch:magazine)
arr[ch - 'a']++;
for(int i = 0; i < ransomNote.size(); i++)
{
// cout<<arr[ransomNote[i] - 'a']<<endl;
arr[ransomNote[i] - 'a']--;
if(arr[ransomNote[i] - 'a'] < 0)
{
return false;
}
}
return flag;
}
第15题. 三数之和
集度实习面试题,寄了 a+b+c = target
首先应想到在for循环中固定一个数,用双指针找另外两个数,起到降for的效果
不返回下标,可以先排序再处理,如果要返回下标也可以用map先记录一下
难点在于去重,a去重应该和前一个比(避免-1,-1,2这种解被漏掉)
b和c去重就双指针往里收缩就行了
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> result;
sort(nums.begin(),nums.end());
int left = 1, right = nums.size()-1;
for(int i = 0; i<nums.size(); ++i)
{
if(nums[i] > 0)
break;
if(i > 0 && nums[i] == nums[i-1])
continue;
left = i + 1;
right = nums.size()-1;
while(right > 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]});
// cout<<nums[i]<<"\t"<<nums[left]<<"\t"<<nums[right]<<endl;
while (right > left && nums[right] == nums[right - 1]) right--;
while (right > left && nums[left] == nums[left + 1]) left++;
left++;
right--;
}
}
}
return result;
}
第18题. 四数之和
三数之和的双指针解法是一层for循环num[i]为确定值,然后循环内有left和right下标作为双指针,找到nums[i] + nums[left] + nums[right] == 0。
四数之和的双指针解法也类似,是两层for循环nums[k] + nums[i]为确定值,依然是循环内有left和right下标作为双指针,找出nums[k] + nums[i] + nums[left] + nums[right] == target的情况
那么一样的道理,五数之和、六数之和等等都采用这种解法。
对于15.三数之和 (opens new window)双指针法就是将原本暴力O(n^3) 的解法,降为O(n^2) 的解法,四数之和的双指针解法就是将原本暴力O(n^4) 的解法,降为O(n^3) 的解法。
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> result;
sort(nums.begin(), nums.end());
int left, right;
for(int i = 0; i < nums.size(); i++)
{
if(nums[i] > 0 && nums[i] > target)
break;
if(i > 0 && nums[i] == nums[i-1])
continue;
for(int j = i + 1; j < nums.size(); j++)
{
if(j > i + 1 && nums[j] == nums[j-1])
continue;
left = j + 1;
right = nums.size() - 1;
while(left < right)
{
// cout<<i<<" "<<j<<" "<<left<<" "<<right<<endl;
if((long)nums[i] + nums[j] + nums[left] + nums[right] > target)
right--;
else if((long)nums[i] + nums[j] + nums[left] + nums[right] < target)
left++;
else
{
// cout<<i<<" "<<j<<" "<<left<<" "<<right<<endl;
result.push_back(vector<int>{nums[i], nums[j], nums[left], nums[right]});
while(right > left && nums[right] == nums[right - 1])right--;
while(right > left && nums[left] == nums[left + 1])left++;
left++;
right--;
}
}
}
}
return result;
}```