文章目录
一、LeetCode 454.四数相加||
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
unordered_map<int,int> map1;
for(int i=0;i<nums1.size();i++){
for(int j=0;j<nums2.size();j++){
if(map1.find(nums1[i]+nums2[j])!=map1.end()){
map1.find(nums1[i]+nums2[j])->second++;
}
else map1.insert(pair(nums1[i]+nums2[j],1));
}
}
int count=0;
for(int i=0;i<nums3.size();i++){
for(int j=0;j<nums4.size();j++){
if(map1.find(-(nums3[i]+nums4[j]))!=map1.end()){
count+=map1.find(0-(nums3[i]+nums4[j]))->second;
}
}
}
return count;
}
};
我自己写的代码,自己看着较好理解。
总体思路:
将四个数组两两分组,分别遍历前两组,记录存在的求和作为键,插入时所有值设为1,表示出现一次,后序遍历时每次遇到相同的键就将值++。
前两个数组遍历完后,设一个count作为最后要返回的值,遍历后两个数组,查找是否有-(nums3[i]+nums4[j])出现,若有,则将count+查找的键对应的值,最后返回。
注意的是这里count每次加的是map1.find(0-(nums3[i]+nums4[j]))->second,而不是1.
二、LeetCode 383.赎金信
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
int record[26]={0};
for(int i=0;i<ransomNote.size();i++){
record[ransomNote[i]-'a']++;
}
for(int i=0;i<magazine.size();i++){
record[magazine[i]-'a']--;
}
for(int i=0;i<26;i++){
if(record[i]>0){
return false;
}
}
return true;
}
};
总体思路较为简单。
三、LeetCode 15.三数之和
双指针法
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> result;
int left,right;
sort(nums.begin(),nums.end());
for(int i=0;i<nums.size()-2;i++){
if(nums[i]>0)return result;
if(i>0 && nums[i]==nums[i-1]){
continue;
}
/*while(i>0 && i<nums.size() && nums[i]==nums[i-1]){
i++;
}判断条件改成这个也行*/
left=i+1;right=nums.size()-1;
while(left<right){
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]});
while(left<right && nums[left]==nums[left+1])left++;
while(left<right && nums[right]==nums[right-1])right--;
right--;
left++;
}
}
}
return result;
}
};
这个题目最复杂的就是对三个数的去重操作。
题目要求:返回的几个数组中,数组中的元素可以重复,但是整个数组不能跟其他数组重复。
总体思路
-
将整个数组先进行升序排序,并设三个数依次为a,b,c
-
将nums数组区域分为两块:
左边,通过遍历确定的a
右边,需要查找的b和c -
先对a进行去重操作,
通过条件:if(i>0 && nums[i]==nums[i-1]){ continue; }
解释:不能用if (nums[i] == nums[i + 1]) { continue; }
,这个条件让i的判定进入了右边区域,干扰到了b和c的选取结果,举例,若{-1,-1,2},则会失效。 -
再进入右边区域,选取b和c,
while(left<right)
做条件限制,若left==right
则b和c就成一个数了,不成立。 -
当找到b+c=-a时,再进行b,c的去重
while(left<right && nums[left]==nums[left+1])left++;
while(left<right && nums[right]==nums[right-1])right--;
这两个条件用于对b和c去重,使同样的a,b,c只存在一个。
注意:此去重条件不能放在while(left<right)
判定条件下的第一个语句,而是要先找到符合条件数组再进行去重,可能出现{0,0,0}的情况而漏解。
- 至此,题目才算完结。
哈希法
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[j], c = -(a + b)
for (int i = 0; i < nums.size(); i++) {
// 排序之后如果第一个元素已经大于零,那么不可能凑成三元组
if (nums[i] > 0) {
break;
}
if (i > 0 && nums[i] == nums[i - 1]) { //三元组元素a去重
continue;
}
unordered_set<int> set;
for (int j = i + 1; j < nums.size(); j++) {
if (j > i + 2
&& nums[j] == nums[j-1]
&& nums[j-1] == nums[j-2]) { // 三元组元素b去重
continue;
}
int c = 0 - (nums[i] + nums[j]);
if (set.find(c) != set.end()) {
result.push_back({nums[i], nums[j], c});
set.erase(c);// 三元组元素c去重
} else {
set.insert(nums[j]);
}
}
}
return result;
}
};
三数之和去重最难理解的就是对b的去重,为什么条件是
if (j > i + 2
&& nums[j] == nums[j-1]
&& nums[j-1] == nums[j-2]) { // 三元组元素b去重
continue;
}
三数之和哈希法为什么是三个连续数相同才去重,可能因为有-4,2,2类似情况,如果只两个连续数相等,就会把第二个2丢掉,从而失败
条件更改为两个连续数去重。
改为两个连续数相等条件0,0,0的条件失败也属于这种情况。
三个连续数相同,加上a已经超过了要求的三元组,所以可以直接去重。
四、LeetCode 18. 四数之和
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> result;
int left,right;
if(nums.size()<4)return {};
sort(nums.begin(),nums.end());
for(int i=0;i<nums.size()-3;i++){
if(nums[i]>target && (target>=0 || nums[i]>=0))break;
if(i>0 && nums[i]==nums[i-1])continue;
for(int j=i+1;j<nums.size()-2;j++){
if(nums[i]+nums[j]>target && (target>=0 || nums[i]>=0))break;
if(j>i+1 && nums[j]==nums[j-1])continue;
left=j+1;right=nums.size()-1;
while(left<right){
if((long) nums[i] + nums[j] + nums[left] + nums[right]<target)left++;
else if((long) nums[i] + nums[j] + nums[left] + nums[right]>target)right--;
else{
result.push_back(vector<int>{nums[i],nums[j],nums[left],nums[right]});
while(left<right && nums[right]==nums[right-1])right--;
while(left<right && nums[left]==nums[left+1])left++;
right--;
left++;
}
}
}
}
return result;
}
};
- 开始时要用
if(nums.size()<4)return {};
进行检查题目中有{0},target=0的情况,会报错
如果不添加这个条件可以将下面i,j的判定条件改为k < nums.size()
,i < nums.size()
,卡哥的代码就是这么写的,我如果不加这个条件会导致出现i<-1的情况,栈溢出,报错。 - 对3,4位数进行判定时,要用强制转换类型(long),用float都不行,会报错,力扣中给的测试用例非常逆天,有很大的数,像91277418,66271374,-90474508这些。
总结
这几天忙着赶课程进度,还参加了校足球赛,训练营这方面有所落下,慢慢赶上来,有些题目是真的难理解,解释也不行,还得自己磨,我还挺喜欢研究题目的过程,但是太耗时间了,如果可以,以后也想做研究,希望我有那个运气和天赋吧。