今天内容依然是哈希方法。第一题是四数相加https://leetcode.cn/problems/4sum-ii/description/,直接的想法是4重循环,时间复杂度爆表,放弃。找卡哥代码随想录。使用的数据容器是unordered_map,分别对两个数组中的数值进行检索。
class Solution {
public:
int fourSumCount(vector& nums1, vector& nums2, vector& nums3, vector& nums4) {
unordered_map mymap;
for(int a : nums1){
for(int b : nums2){
mymap[a + b]++;
}
}
int result = 0;
for(int c : nums3){
for(int d : nums4){
int targe = -(c + d);
if(mymap.find(targe) != mymap.end()){
result += mymap[targe];
}
}
}
return result;
}
};
第二题是赎金信https://leetcode.cn/problems/ransom-note/description/,很奇怪的名字,感觉和做过的字母异位是一个壳子。直接用数组解了,先记录magazine中的元素出现情况,在记录信中的出现情况,只要信中元素出现次数多,返回false。代码很简单,编译一遍过了。
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
int a[26] = {0};
for(int i = 0; i < magazine.length(); i++){
a[magazine[i] - 'a']++;
}
for(int j = 0; j < ransomNote.length(); j++){
a[ransomNote[j] - 'a']--;
}
for(int b = 0; b < 26; b++){
if(a[b] < 0) return false;
}
return true;
}
};
第三题是三数之和https://leetcode.cn/problems/3sum/description/,感觉用哈希法有点麻烦,尝试直接遍历。问题出在如何把遍历到的结果填充到vector中,查阅资料发现是使用push_back,结果错误,未去重。
class Solution {
public:
vector> threeSum(vector& nums) {
vector> result;
int count = 0;
for(int i = 0; i < nums.size() - 2; i++){
for(int j = i + 1; j < nums.size() - 1; j++){
for(int k = j + 1; k < nums.size(); k++){
if(nums[i] + nums[j] + nums[k] == 0){
count++;
result.push_back(vector{nums[i], nums[j], nums[k]});
}
}
}
}
return result;
}
};
求助卡哥代码随想录,卡哥给出了两个思路,哈希与双指针,做了一些双指针的题,感到这种方法属实不太好想。哈希法也很麻烦,去重的主要问题在于数组的排序,跟着卡哥写了一版哈希法的代码,确实不容易。
class Solution {
public:
vector> threeSum(vector& nums) {
vector> result;
sort(nums.begin(), nums.end());//排序我没想到
for(int i = 0; i < nums.size(); i++){
if (nums[i] > 0) break;
if (i > 0 && nums[i] == nums[i - 1]) continue;
unordered_set 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]) continue;
int c = -(nums[i] + nums[j]);
if(set.find(c) != set.end()){
result.push_back({nums[i], nums[j], c});
set.erase(c);
}
else set.insert(nums[j]);
}
}
return result;
}
};
下面就是双指针法,核心问题也在去重逻辑的把握上。
class Solution {
public:
vector> threeSum(vector& nums) {
vector> 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[left] + nums[right] > 0) right--;
else if(nums[i] + nums[left] + nums[right] < 0) left++;
else {
result.push_back(vector{nums[i], nums[left], nums[right]});
while(right > left && nums[right] == nums[right - 1]) right--;
while(right > left && nums[left] == nums[left + 1]) left++;//对left、right去重
right--;left++;
}
}
}
return result;
}
};
第四题是四数之和https://leetcode.cn/problems/4sum/description/,和上一题很相似,但还是不会求助卡哥代码随想录,思路和三数之和一致,不过外层还要套一个for循环。
class Solution {
public:
vector> fourSum(vector& nums, int target) {
vector> result;
sort(nums.begin(), nums.end());
for (int k = 0; k < nums.size(); k++){
if(nums[k] > target && nums[k] >= 0 && target >= 0) break;
if (k > 0 && nums[k] == nums[k - 1]) continue;
for (int i = k + 1; i < nums.size(); i++){
if(nums[k] + nums[i] > target && nums[k] + nums[i] >= 0 && target >= 0) break;
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 {result.push_back(vector{nums[k], nums[i], nums[left], nums[right]});
while(right > left && nums[right] == nums[right - 1]) right--;
while(right > left && nums[left] == nums[left + 1]) left++;
right--; left++;}
}
}
}
return result;
}
};
有史以来写过最长的代码。
那么哈希方法章节今天就结束了,我个人感觉哈希方法的应用面比较有针对性,判断元素是否在集合中,以后遇到此类题要往这方面想,同时做了一类的n数之和,再次巩固了双指针法的使用。此外也学到了数组,set,map作为哈希表的应用,本节的知识密度还是很大的。