代码随想录算法训练营第七天| 454.四数相加II 383. 赎金信 15. 三数之和 18. 四数之和
454.四数相加II
给你四个整数数组 nums1
、nums2
、nums3
和 nums4
,数组长度都是 n
,请你计算有多少个元组 (i, j, k, l)
能满足:
0 <= i, j, k, l < n
nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0
题目链接:454. 四数相加 II - 力扣(LeetCode)
思路:当遇到需要确认元素是否重复出现的问题时,考虑用map哈希解决问题。将前两个数组的和存入map1,并用value表示这个和出现的对数。然后查询-(num3[k]+nums4[l])是否出现在map中。
注意:
用insert方法重复插入同一key值的键值对并不会导致覆盖,即会插入失败。
用find方法查找元素会比count方法快很多。
用下标访问map,即使改下标下没有内容,我们也能对value进行访问,不用区别对待。
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
map<int,int> map1;
int count=0;
for(int i=0;i<nums1.size();i++){
for(int j=0;j<nums2.size();j++){
// auto iter=map1.find(nums1[i]+nums2[j]);
// if(iter!=map1.end())
// if(map1.count(nums1[i]+nums2[j]))
map1[nums1[i]+nums2[j]]++;
// else
// map1.insert(pair<int,int>(nums1[i]+nums2[j],1)); //无需区别对待
// map1.insert(pair<int,int>(nums1[i]+nums2[j],1));
}
}
for(int k=0;k<nums3.size();k++){
for(int l=0;l<nums4.size();l++){
// auto iter=map1.find(-(nums3[k]+nums4[l]));
// if(iter!=map1.end()){
if(map1.find(0-(nums3[k]+nums4[l]))!=map1.end()){
count+=map1[0-(nums3[k]+nums4[l])];
}
}
}
return count;
}
};
注意下面这种写法,同样的算法,却能比我的版本快一倍多。
class Solution {
public:
int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {
unordered_map<int, int> umap; //key:a+b的数值,value:a+b数值出现的次数
// 遍历大A和大B数组,统计两个数组元素之和,和出现的次数,放到map中
for (int a : A) {
for (int b : B) {
umap[a + b]++;
}
}
int count = 0; // 统计a+b+c+d = 0 出现的次数
// 在遍历大C和大D数组,找到如果 0-(c+d) 在map中出现过的话,就把map中key对应的value也就是出现次数统计出来。
for (int c : C) {
for (int d : D) {
if (umap.find(0 - (c + d)) != umap.end()) {
count += umap[0 - (c + d)];
}
}
}
return count;
}
};
383. 赎金信
给你两个字符串:ransomNote
和 magazine
,判断 ransomNote
能不能由 magazine
里面的字符构成。
如果可以,返回 true
;否则返回 false
。
magazine
中的每个字符只能在 ransomNote
中使用一次。
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
map<char,int>map1;
map<char,int>map2;
for(char ch:ransomNote){
map1[ch]++;
}
for(char ch:magazine){
map2[ch]++;
}
for(char ch:ransomNote){
if(map1[ch]>map2[ch])
return false;
}
return true;
}
};
更好的写法:
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
// 利用哈希表
unordered_map<char,int> u_m;
for(auto ch:magazine)
++u_m[ch];
for(auto ch:ransomNote)
{
if(u_m[ch]==0)
return false;
--u_m[ch];
}
return true;
}
};
15. 三数之和
给你一个整数数组 nums
,判断是否存在三元组 [nums[i], nums[j], nums[k]]
满足 i != j
、i != k
且 j != k
,同时还满足 nums[i] + nums[j] + nums[k] == 0
。请
你返回所有和为 0
且不重复的三元组。
注意:答案中不可以包含重复的三元组。
思路:正常哈希法会很困难,因为去重的操作很复杂。用双指针法可以有效的解决这个问题。同时,用sort函数先排序原数据的思想要学会(双指针法是一定要排序的)。尽管要求三元组不能重复,但注意三元组内部可以重复,因此在去重a时要注意,要比较a的上一个元素而非a的下一个元素。
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> result;
sort(nums.begin(),nums.end());
for(int i=0;i<nums.size();i++){
if(nums[i]>0){
return result;
}
if(i>0&&nums[i]==nums[i-1])
continue;
int left=i+1;
int right=nums.size()-1;
while(right>left){
if(nums[i]+nums[right]+nums[left]>0)
{
right--;
}
else if(nums[i]+nums[right]+nums[left]<0)
{
left++;
}
else{
result.push_back(vector<int>{nums[i],nums[left],nums[right]});
while(right>left&&nums[right]==nums[right-1])right--; //b、c去重
while(right>left&&nums[left]==nums[left+1])left++;
right--; //找到答案在移动b、c
left++;
}
}
}
return result;
}
};
18. 四数之和
给你一个由 n
个整数组成的数组 nums
,和一个目标值 target
。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]]
(若两个四元组元素一一对应,则认为两个四元组重复):
0 <= a, b, c, d < n
a
、b
、c
和d
互不相同nums[a] + nums[b] + nums[c] + nums[d] == target
思路:和三数之和思路类似,只是从左动右固定变成左右都动。注意,左边的去重一定要在右边移动之前进行,否则会被[0,0,0,0]判溢出。
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> result;
if(nums.size()<4){
return result;
}
sort(nums.begin(),nums.end());
for(int i=0;i<nums.size()-3;i++){
if(nums[i]>target&&nums[i]>=0)
break;
if(i>0&&nums[i]==nums[i-1]){
continue;
} //左侧去重必须在for之前进行
for(int j=nums.size()-1;j>=i+3;j--){
if(j<nums.size()-1&&nums[j]==nums[j+1]){
continue;
}
int left=i+1;
int right=j-1;
while(right>left){
if((long)nums[i]+nums[left]+nums[right]+nums[j]>target)right--;
else if((long)nums[i]+nums[left]+nums[right]+nums[j]<target)left++;
else{
result.push_back(vector<int>{nums[i],nums[left],nums[right],nums[j]});
while(right>left&&nums[right]==nums[right-1])right--;
while(right>left&&nums[left]==nums[left+1])left++;
left++;right--;
}
}
}
}
return result;
}
};
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端