代码随想录day7 ● 454.四数相加II ● 383. 赎金信 ● 15. 三数之和 ● 18. 四数之和 ● 总结

454. 四数相加 II

暴力解法(超出时间限制):

 1 class Solution {
 2 public:
 3     int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
 4         int n = nums1.size();
 5         int result = 0;
 6         for (int i = 0; i < n; i++){
 7             for (int j = 0; j < n; j++){
 8                 for (int k = 0; k < n; k++){
 9                     for (int z = 0; z < n; z++){
10                         if (nums1[i] + nums2[j] + nums3[k] + nums4[z] == 0){
11                             result++;
12                         }
13                     }
14                 }
15             }
16         }
17         return result;
18     }
19 };

哈希法:

第一步:定义一步unordered_map,key放a和b两数之和,value放a和b两数之和出现的次数;

第二步:遍历前两数组,记录两个数组元素之和以及出现的次数,umap[a+b]++;

第三步:遍历后两数组,记录(0 - (c+d))出现的次数;

第四步:count += umap[0 - (c + d)];

第五步:返回count;

 1 class Solution {
 2 public:
 3     int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {
 4         //创建unordered_map用于保存nums1[i] + nums2[j]出现的次数
 5         //key用于记录a + b的值,val用于记录a + b出现的次数
 6         unordered_map<int, int> umap;
 7         //用于记录a + b = - (c + d)的次数
 8         int count = 0;
 9         //用于记录a + b出现的次数
10         for (int a : A){
11             for (int b : B){
12                 //记录出现次数
13                 umap[a + b]++;
14             }
15         }
16         //判断c + d出现的次数
17         for (int c : C){
18             for (int d : D){
19                 if (umap.find(0 - (c + d)) != umap.end()){
20                     count += umap[0 - (c + d)];
21                 }
22             }
23         }
24         return count;
25     }
26 };

383. 赎金信

自己写的类似242.有效的字母异位词的解法:

 1 class Solution {
 2 public:
 3     bool canConstruct(string ransomNote, string magazine) {
 4         int res[26] = {0};
 5         //记录ransomNote中字母出现的次数
 6         for (int i = 0; i < ransomNote.size(); i++){
 7             res[ransomNote[i] - 'a']--;
 8         }
 9         //减去magazine中字母出现的次数
10         for (int i = 0; i < magazine.size(); i++){
11             res[magazine[i] - 'a']++;
12         }
13         //判断数组中的每个数是否大于0
14         for (int i = 0; i < 26; i++){
15             if(res[i] < 0){
16                 return false;
17             }
18         }
19         return true;
20     }
21 };

卡哥暴力解法:

 1 // 时间复杂度: O(n^2)
 2 // 空间复杂度:O(1)
 3 class Solution {
 4 public:
 5     bool canConstruct(string ransomNote, string magazine) {
 6         //遍历两个数组,当magazine当中出现ransomNote中的字母消去ransomNote中的该字母
 7         for (int i = 0; i < magazine.length(); i++) {
 8             for (int j = 0; j < ransomNote.length(); j++) {
 9                 // 在ransomNote中找到和magazine相同的字符
10                 if (magazine[i] == ransomNote[j]) {
11                     ransomNote.erase(ransomNote.begin() + j); // ransomNote删除这个字符
12                     break;
13                 }
14             }
15         }
16         // 如果ransomNote为空,则说明magazine的字符可以组成ransomNote
17         if (ransomNote.length() == 0) {
18             return true;
19         }
20         return false;
21     }
22 };

哈希解法:

看起来和自己写的差不多。

 1 // 时间复杂度: O(n)
 2 // 空间复杂度:O(1)
 3 class Solution {
 4 public:
 5     bool canConstruct(string ransomNote, string magazine) {
 6         int record[26] = {0};
 7         //add
 8         if (ransomNote.size() > magazine.size()) {
 9             return false;
10         }
11         for (int i = 0; i < magazine.length(); i++) {
12             // 通过recode数据记录 magazine里各个字符出现次数
13             record[magazine[i]-'a'] ++;
14         }
15         for (int j = 0; j < ransomNote.length(); j++) {
16             // 遍历ransomNote,在record里对应的字符个数做--操作
17             record[ransomNote[j]-'a']--;
18             // 如果小于零说明ransomNote里出现的字符,magazine没有
19             if(record[ransomNote[j]-'a'] < 0) {
20                 return false;
21             }
22         }
23         return true;
24     }
25 };

*15. 三数之和

第一眼思路:

难度较大,没有思路,需着重学习

双指针法:

 代码如下:

 1 class Solution {
 2 public:
 3     vector<vector<int>> threeSum(vector<int>& nums) {
 4         vector<vector<int>> result;
 5         //对nums数组进行排序
 6         sort(nums.begin(), nums.end());
 7         for (int i = 0; i < nums.size(); i++){
 8             //第一个大于零,则不存在这样的数组
 9             if(nums[i] > 0){
10                 break;
11             }
12             //三元组第一个元素去重
13             if (i > 0 && nums[i] == nums[i - 1]){
14                 continue;
15             }
16             //定义双指针用于收缩
17             int left = i + 1;
18             int right = nums.size() - 1;
19             while (right > left){
20                 if (nums[i] + nums[left] + nums[right] > 0){
21                     right--;
22                 } else if (nums[i] + nums[left] + nums[right] < 0){
23                     left++;
24                 } else {
25                     //得到结果集
26                     result.push_back(vector<int>{nums[i], nums[left], nums[right]});
27                     while (right > left && nums[left] == nums[left + 1]) left++;
28                     while (right > left && nums[right] == nums[right - 1]) right--;
29                     //得到结果,双指针同时收缩
30                     left++;
31                     right--;
32                 }
33             }
34         }
35         return result;
36     }
37 };

 18. 四数之和

类似三数之和,利用双指针的方法,代码如下:

 1 class Solution {
 2 public:
 3     vector<vector<int>> fourSum(vector<int>& nums, int target) {
 4         vector<vector<int>> result;
 5         //对nums数组进行排序
 6         sort(nums.begin(), nums.end());
 7         for (int i = 0; i < nums.size(); i++){
 8             //剪枝处理
 9             if(nums[i] > target && nums[i] >= 0){
10                 break;
11             }
12             //i去重
13             if(i > 0 && nums[i] == nums[i - 1]){
14                 continue;
15             }
16             for (int j = i + 1; j < nums.size(); j++){
17                 //2级剪枝操作
18                 if (nums[i] + nums[j] > target && nums[i] + nums[j] >= 0) {
19                     break;
20                 }
21                 //j去重
22                 if(j > i + 1 && nums[j] == nums[j - 1]){
23                     continue;
24                 }
25                 int left = j + 1;
26                 int right = nums.size() - 1;
27                 while (right > left){
28                     if ((long)nums[i] + nums[j] + nums[left] + nums[right] < target){
29                         left++;
30                     } else if ((long)nums[i] + nums[j] + nums[left] + nums[right] > target){
31                         right--;
32                     } else {
33                         result.push_back(vector<int>{nums[i], nums[j], nums[left], nums[right]});
34                         while (right > left && nums[right] == nums[right - 1]) right--;
35                         while (right > left && nums[left] == nums[left + 1]) left++;
36                         //双指针同时收缩
37                         left++;
38                         right--;
39                     }
40                 }
41             }
42         }
43         return result;
44     }
45 };

 

posted @ 2022-09-30 18:56  aijiajia0509  阅读(29)  评论(0)    收藏  举报