454.四数相加II
本题给出四个数组要求计算有多少个不同的和为0的元组,由于只要求计算元组数量而不要求去重,所以相对来说简单一些,具体思路就是遍历前两个数组的元素将其和
a+b
加入到map
中(用map
是因为要既存值又存下标),在map
中a+b
的值作为key
而出现的次数作为value
再遍历后两个数组所有的元素和c+d
,在map
中找如果有满足a+b+c+d=0
的项,则此项的value
即为符合条件的元组的个数
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2,
vector<int>& nums3, vector<int>& nums4) {
unordered_map<int, int>m;
int count=0;
for (int i = 0; i < nums1.size(); i++) {
for (int j = 0; j < nums2.size(); j++) {
m[nums1[i] + nums2[j]]++;//key是值,value是出现过的次数
}
}
for (int i = 0; i < nums3.size(); i++) {
for (int j = 0; j < nums4.size(); j++) {
if (m.find(-nums3[i] - nums4[j]) != m.end()) {
count += m[-nums3[i]-nums4[j]];
}
}
}
return count;
}
};
383.赎金信
此题思路与242.有效字母异位词相似,以数组作哈希表
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
int res[26];
for (int i = 0; i < magazine.length(); i++) {
res[magazine[i] - 'a']++;
}
for (int i = 0; i < ransomNote.length(); i++) {
res[ransomNote[i] - 'a']--;
}
for (int i = 0; i < 26; i++) {
if (res[i] < 0)return 0;
}
return 1;
}
};
15.三数之和
甚至Carl哥这期视频的标题是梦破碎的地方
此题与454.三数之和有很大区别,因为这题是在一个数组里而且还需要去重,用哈希法解决较难,推荐使用双指针法(虽然我觉得也很难),具体思路就是外面一层
for
循环用i
遍历数组,循环内部定义两个变量left
和right
,每次循环在i
不动的前提下收缩两个指针,来得到满足a+b+c=0
条件的元组,内部也涉及到去重和剪枝的操作
对a
去重时一定要满足nums[i] == nums[i - 1]
而不是nums[i] == nums[i + 1]
(相当于i
与left
比较,会丢结果集)eg:结果集为[-1,-1,2]时,nums[i] == nums[i + 1]
会将此结果集跳过,但其实这个结果集是满足条件的
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>>res;
int left = 0;
int right = 0;
//a=nums[i],b=nums[left],c=nums[right]
sort(nums.begin(), nums.end());//排序后方便去重
for (int i = 0; i < nums.size(); i++) {
if (nums[i] > 0)return res;
//后面的数全大于0无符合结果(对a剪枝)
if (i>0&&nums[i] == nums[i - 1])continue;
//如果当前的a和前一个重复就遍历下一个(对a去重)
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 {
res.push_back({ 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++;
}
left++;
right--;
}
}
}
return res;
}
};
18.四数之和
与15.三数之和类似,不同的是用两个
for
循环分别固定前两个数nums[k]
和nums[i]
,再用left
和right
找后两个数,涉及到二级去重和剪枝
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
vector<vector<int>>res;
for (int k = 0; k < nums.size(); k++) {
//对k剪枝
if (nums[k] > target&&nums[k] >= 0) {
break;
}
//对k去重
if (k > 0 && nums[k] == nums[k - 1]) {
continue;
}
for (int i = k + 1; i < nums.size(); i++) {
//对i剪枝
if (nums[i] + nums[k] > target&&nums[i] + nums[k] >= 0) {
break;
}
//对i去重
if (i>k+1&&nums[i] == nums[i - 1])
continue;
//三数之和思路,双指针
int left = i+1;
int right = nums.size() - 1;
while (right>left)
{
if ((long)nums[k] + nums[i] + nums[left] + nums[right] > target)
right--;
else if ((long)nums[k] + nums[i] + nums[left] + nums[right] < target)
left++;
else {
res.push_back({ nums[k],nums[i],nums[left],nums[right] });
//对left,right去重
while (right > left&&nums[right] == nums[right-1])
{
right--;
}
while (right>left&&nums[left]==nums[left+1])
{
left++;
}
right--;
left++;
}
}
}
}
return res;
}
};