代码随想录第五十八期day07
题目1: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
示例 1:
输入:nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2]
输出:2
解释:
两个元组如下:
- (0, 0, 0, 1) -> nums1[0] + nums2[0] + nums3[0] + nums4[1] = 1 + (-2) + (-1) + 2 = 0
- (1, 1, 0, 0) -> nums1[1] + nums2[1] + nums3[0] + nums4[0] = 2 + (-1) + (-1) + 0 = 0
示例 2:
输入:nums1 = [0], nums2 = [0], nums3 = [0], nums4 = [0]
输出:1
提示:
n == nums1.length
n == nums2.length
n == nums3.length
n == nums4.length
1 <= n <= 200
-2^ 28 <= nums1[i], nums2[i], nums3[i], nums4[i] <= 2^28
解析:本题乍一看很简单,但是真正要写会发现很困难,题意就是从给到的四个数组中,一个数组取一个元素,再对这四个元素求和,使得他们和为0,即得一种,题目要返回的是从这四个数组里面一共能找到多少个这样的元组,使得他们和为0,对于本题我优先想到4层for循环,那么他的时间复杂度为O(N^4)这个复杂度相当的大,可想而知,超时了,代码如下:
int fourSumCount(int* nums1, int nums1Size, int* nums2, int nums2Size, int* nums3, int nums3Size, int* nums4, int nums4Size) {
int count=0;
for(int i = 0;i<nums1Size;i++){
for(int j = 0;j<nums1Size;j++){
for(int k = 0;k<nums1Size;k++){
for(int r = 0;r<nums4Size;r++){
if(nums1[i]+nums2[j]+nums3[k]+nums4[r] == 0)count++;
}
}
}
}
return count;
}
然后实在没思路,最后去看了Carl哥讲解,思路就是降o(n^ 4)为o(n^2)。归并排序的思想,两两求和来实现降为o(n ^ 2);由于不知道两个数组中元素求和后有多少个元素,所以用了链表来保存。本题用了一个hashmap,hashmap里面定义的key用来存和,value用来存出现了几次,这样就能在后面方便统计。解题步骤:
本题解题步骤:
1首先定义 一个unordered_map,key放a和b两数之和,value 放a和b两数之和出现的次数。
2遍历大A和大B数组,统计两个数组元素之和,和出现的次数,放到map中。
3定义int变量count,用来统计 a+b+c+d = 0 出现的次数。
4再遍历大C和大D数组,找到如果 0-(c+d) 在map中出现过的话,就用count把map中key对应的value也就是出现次数统计出来。
5最后返回统计值 count 就可以了。
代码如下:
// 哈希表大小
const int HASH_SIZE = 101;
typedef struct node {
int val;
int count;
struct node *next;
} node, *HashMap;
// 哈希表插入
void hash_insert(HashMap hashmap[], int val) {
int idx = val < 0 ? (-val) % HASH_SIZE : val % HASH_SIZE, count = 0;
node *p = hashmap[idx];
while (p->next != NULL) {
p = p->next;
if (p->val == val) {
(p->count)++;
return;
}
}
node *new = malloc(sizeof(node));
new->val = val;
new->count = 1;
new->next = NULL;
p->next = new;
return;
}
// 哈希表查找
int hash_search(HashMap hashmap[], int val) {
int idx = val < 0 ? (-val) % HASH_SIZE : val % HASH_SIZE;
node *p = hashmap[idx];
while (p->next != NULL) {
p = p->next;
if (p->val == val) return p->count;
}
return 0;
}
int fourSumCount(int* nums1, int nums1Size, int* nums2, int nums2Size, int* nums3, int nums3Size, int* nums4, int nums4Size){
// 初始化哈希表
HashMap hashmap[HASH_SIZE];
for (int i = 0; i < HASH_SIZE; i++) {
hashmap[i] = malloc(sizeof(node));
hashmap[i]->next = NULL;
}
// 统计两个数组元素之和的负值和出现的次数,放到哈希表中
int count = 0, num;
for (int i = 0; i < nums1Size; i++) {
for(int j = 0; j < nums2Size; j++) {
num = - nums1[i] - nums2[j];
hash_insert(hashmap, num);
}
}
// 统计另外两个数组元素之和,查找哈希表中对应元素的出现次数,加入总次数
for (int i = 0; i < nums3Size; i++) {
for(int j = 0; j < nums4Size; j++) {
num = nums3[i] + nums4[j];
count += hash_search(hashmap, num);
}
}
return count;
}
题目2:383. 赎金信
题目:给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。
如果可以,返回 true ;否则返回 false 。
magazine 中的每个字符只能在 ransomNote 中使用一次。
示例 1:
输入:ransomNote = “a”, magazine = “b”
输出:false
示例 2:
输入:ransomNote = “aa”, magazine = “ab”
输出:false
示例 3:
输入:ransomNote = “aa”, magazine = “aab”
输出:true
提示:
1 <= ransomNote.length, magazine.length <= 105
ransomNote 和 magazine 由小写英文字母组成
解析:本题比较简单,直接hash映射到数组下标就能完成,和之前的有道题目很像,242. 有效的字母异位词思路一致,都是问能不能由另一个来组成,代码如下:
bool canConstruct(char* ransomNote, char* magazine) {
//hash映射
int Hash_1[26]={0};
int Hash_2[26]={0};
for(int i = 0;i<strlen(ransomNote);i++){
Hash_1[((int)ransomNote[i])-97]++;
}
for(int i = 0;i<strlen(magazine);i++){
Hash_2[((int)magazine[i])-97]++;
}
for(int i = 0;i<26;i++){
if(Hash_1[i] != 0){
if(Hash_1[i] > Hash_2[i])return false;
}
}
return true;
}
题目三:15. 三数之和
题目:给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。
示例 2:
输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。
示例 3:
输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。
提示:
3 <= nums.length <= 3000
-105 <= nums[i] <= 105
解析:本题中重点在于要找到的是不重复的三元组,使得他们和为0,然后输出这些三元组,对于这个问题,我们可以用双指针法来解决,即先给原来的数据排序,再用一个指针来遍历,其余两个指针left,right来查抄所符合条件的三元组,和大了就right–,和小了就left++;这样当条件为left>right时候就可以结束查找,在走遍历的指针,直到查找完,就能实现三数之和,cpp代码如下:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> result;
int n = nums.size();
if (n < 3) return result;
sort(nums.begin(), nums.end());
for (int i = 0; i < n - 2; i++) {
if (i > 0 && nums[i] == nums[i - 1]) continue;
int left = i + 1, right = n - 1;
int target = -nums[i];
while (left < right) {
int sum = nums[left] + nums[right];
if (sum == target) {
result.push_back({nums[i], nums[left], nums[right]});
while (left < right && nums[left] == nums[left + 1]) left++;
while (left < right && nums[right] == nums[right - 1]) right--;
left++;
right--;
} else if (sum < target) {
left++;
} else {
right--;
}
}
}
return result;
}
};


被折叠的 条评论
为什么被折叠?



