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
分析及思路
我们是四个数组相加最终等于0,我们可以两个两个的进行相加,a[]+b[]然后c[]+d[],即a[]+b[]等于
-(c[]+d[]),就转换成,查哈希表格了,因为要存储下标和出现的次数,所以我们用map来解决问题。
详细请看:代码随想录 (programmercarl.com)
代码及注释
typedef struct { // 定义一个结构体
int key; // 键
int value; // 值
UT_hash_handle hh; // 使这个结构体可哈希化
} map; // 结构体类型为map
int fourSumCount(int* nums1, int nums1Size, int* nums2, int nums2Size, int* nums3, int nums3Size, int* nums4, int nums4Size){
map* hashMap = NULL; // 声明一个指向 map 结构体的指针 hashMap,初始化为 NULL
map* temp = NULL; // 声明一个指向 map 结构体的指针 temp,初始化为 NULL
int key; // 声明一个整型变量 key
int count = 0; // 声明一个整型变量 count,初始化为 0
for(int i=0;i<nums1Size;i++){ // 循环,从 i=0 开始,直到 i<nums1Size 为止,每次递增 i
for(int j=0;j<nums2Size;j++){ // 嵌套循环,从 j=0 开始,直到 j<nums2Size 为止,每次递增 j
key = nums1[i]+nums2[j]; // 计算 key 的值为 nums1[i] 加上 nums2[j]
HASH_FIND_INT(hashMap,&key,temp); // 在 hashMap 中查找 key 对应的元素,并将结果存储在 temp 中
if(temp){ // 如果 temp 不为空
temp->value++; // temp 指向的元素的 value 值加一
}
else{ // 如果 temp 为空
map* temp1 = (map*)malloc(sizeof(map)); // 分配内存空间,大小为 map 结构体的大小,并将地址赋给 temp1
temp1->value = 1; // 设置 temp1 指向的元素的 value 值为 1
temp1->key = key; // 设置 temp1 指向的元素的 key 值为 key
HASH_ADD_INT(hashMap,key,temp1); // 将 temp1 插入到 hashMap 中,key 为 key
}
}
}
for(int i=0;i<nums3Size;i++){ // 循环,从 i=0 开始,直到 i<nums3Size 为止,每次递增 i
for(int j=0;j<nums4Size;j++){ // 嵌套循环,从 j=0 开始,直到 j<nums4Size 为止,每次递增 j
key = 0-(nums3[i] +nums4[j]); // 计算 key 的值为 0 减去 nums3[i] 加上 nums4[j]
HASH_FIND_INT(hashMap,&key,temp); // 在 hashMap 中查找 key 对应的元素,并将结果存储在 temp 中
if(temp){ // 如果 temp 不为空
count = count + temp->value; // 将 count 值加上 temp 指向的元素的 value 值
}
}
}
return count; // 返回 count 的值
}
383. 赎金信
题目链接/文章讲解:代码随想录
给你两个字符串:
ransomNote
和magazine
,判断ransomNote
能不能由magazine
里面的字符构成。如果可以,返回
true
;否则返回false
。
magazine
中的每个字符只能在ransomNote
中使用一次。
分析及思路
和字母异位词一样使用数组哈希表,我们用大小为26的数组存储所有的字母,将第二个字母的频率存入数组中,然后用第一个字母进行频率的减法操作,若有一个小于0则返回false否则返回true,在此之前我们可以看一看第一个数组是否大于第二个数组,若大于则一定不存在,这样可以增加我们的代码效率。
代码及注释
bool canConstruct(char* ransomNote, char* magazine) { // 定义函数,参数为赎金信和杂志字符串
int hash[26] = {0}; // 创建一个包含26个元素的哈希表,初始化为0
if(strlen(ransomNote) > strlen(magazine)) // 如果赎金信的长度大于杂志的长度,返回false
return false;
for(int i = 0;i < strlen(magazine);i++){ // 遍历杂志字符串
hash[magazine[i]-'a']++; // 将杂志字符串中每个字符出现的次数记录到哈希表中
}
for(int i = 0;i < strlen(ransomNote);i++){ // 遍历赎金信字符串
hash[ransomNote[i]-'a']--; // 将赎金信字符串中每个字符出现的次数从哈希表中减去
}
for(int i= 0;i < 26;i++){ // 遍历哈希表
if(hash[i] < 0) // 如果哈希表中有任何元素小于0,说明赎金信中出现了杂志中没有的字符,返回false
return false;
}
return true; // 如果以上条件都不满足,返回true
}
15. 三数之和
题目链接/文章讲解/视频讲解:代码随想录
给你一个整数数组
nums
,判断是否存在三元组[nums[i], nums[j], nums[k]]
满足i != j
、i != k
且j != k
,同时还满足nums[i] + nums[j] + nums[k] == 0
。请你返回所有和为
0
且不重复的三元组。注意:答案中不可以包含重复的三元组。
双指针
分析及思路
这是一个在数组中求和的问题,可以使用三个指针,指向不同的元素,为了防止重复我们可以进行排序然后在求和,方便去重。类似滑动窗口。
代码及注释
int cmp(const void* ptr1, const void* ptr2) { // 定义一个比较函数,用于qsort排序
return *((int*)ptr1) > *((int*)ptr2); // 比较两个整数的大小
}
int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) { // 定义一个函数,用于求解三数之和
int** arr = (int**)malloc(sizeof(int*)*18000); // 为存储结果开辟空间
int arr_Top = 0; // 用于记录结果数组的当前索引
if(numsSize < 3){ // 如果数组长度小于3
*returnSize = 0; // 返回的数组大小为0
return arr; // 返回空数组
}
qsort(nums, numsSize, sizeof(int), cmp); // 对输入数组进行排序
for(int i = 0;i<numsSize-2;i++){ // 遍历数组
if(nums[i] > 0) // 如果当前元素大于0,跳出循环
break;
if(i>0&&nums[i]==nums[i-1]) // 如果当前元素与前一个元素相等,跳过当前循环
continue;
int left = i + 1,right = numsSize-1; // 初始化左右指针
while(left < right){ // 当左指针小于右指针时循环
int sum = nums[i] + nums[left] + nums[right]; // 计算三数之和
if(sum < 0) // 如果和小于0,左指针右移
left++;
else if(sum > 0) // 如果和大于0,右指针左移
right--;
else{ // 如果和等于0
int* a = (int*)malloc( sizeof(int) * 3 ); // 为当前解分配空间
a[0] = nums[i]; // 记录第一个数
a[1] = nums[left]; // 记录第二个数
a[2] = nums[right]; // 记录第三个数
arr[arr_Top++] = a; // 将当前解存入结果数组
while( (left<right) && (nums[left]==nums[left+1]) ) // 跳过重复的左指针
left++;
while( (left<right) && nums[right]==nums[right-1] ) // 跳过重复的右指针
right--;
left++; // 左指针右移
right--; // 右指针左移
}
}
}
//设定返回的数组大小
*returnSize = arr_Top; // 设置返回数组的大小
*returnColumnSizes = (int*)malloc(sizeof(int) * arr_Top); // 为返回的列大小数组分配空间
int z;
for(z = 0; z < arr_Top; z++) { // 遍历结果数组
(*returnColumnSizes)[z] = 3; // 设置每个解的列大小为3
}
return arr; // 返回结果数组
}
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
你可以按 任意顺序 返回答案 。
分析及思路
和三数之和类似,我们还是使用,我们已久使用双指针,只是多增加了一个for循环。
代码及注释
int cmp(const void* ptr1, const void* ptr2) { // 定义一个比较函数,用于qsort排序
return *((int*)ptr1) > *((int*)ptr2); // 比较两个整数的大小
}
定义一个比较函数cmp,用于在qsort排序时进行比较。
int** fourSum(int* nums, int numsSize, int target, int* returnSize, int** returnColumnSizes) {
int arr_Top = 0;
int** arr = (int**)malloc(sizeof(int*)*1001);
用于存储结果的二维数组arr,初始分配1001个指针大小的空间。
if(numsSize < 4){
*returnSize = 0;
return arr;
}
如果输入数组大小小于4,则直接返回空数组。
qsort(nums, numsSize, sizeof(int), cmp); // 对输入数组进行排序
使用定义的比较函数cmp对输入数组进行排序。
for(int k=0;k<numsSize-3;k++){
if(nums[k]>target&&target>0){
break;
}
if( (k>0) && (nums[k]==nums[k-1]) )
continue;
对于每个下标k,进行去重和边界判断。
for(int i=k+1;i<numsSize-2;i++){
if( (nums[i]>target) && (target>0) )
break;
if( (i>k+1) && (nums[i]==nums[i-1]) )
continue;
对于每个下标i,进行去重和边界判断。
int left = i+1,right = numsSize - 1;
定义左右指针left和right。
while(left < right){
long sum = (long)nums[k] + nums[i] + nums[left] + nums[right];
计算当前四个数的和sum。
if(sum > target)
right--;
else if(sum < target){
left++;
}
else{
int* a = (int*)malloc(sizeof(int)*4);
a[0] = nums[k];
a[1] = nums[i];
a[2] = nums[left];
a[3] = nums[right];
将符合条件的四个数存入临时数组a中,并加入结果数组arr。
arr[arr_Top++] = a;
更新结果数组的长度。
while( (left < right) && (nums[left]==nums[left+1]) )
left++;
while( (left < right) && (nums[right]==nums[right-1]) )
right--;
进行去重处理。
left++;
right--;
移动左右指针。
}
}
}
}
遍历所有可能的组合,找到符合条件的四个数的组合。
*returnSize = arr_Top;
更新返回结果的大小。
*returnColumnSizes = (int*)malloc(sizeof(int)*arr_Top);
为返回的列大小数组分配内存。
for(int i=0;i<arr_Top;i++)
(*returnColumnSizes)[i] = 4;
设置返回的列大小数组的值为4。
return arr;
返回结果数组arr。
}
总结
今天的题目还得在看一看,要灵活运用双指针操作。