代码随想录算法训练营第42期 第七天 | LeetCode454.四数相加II、383. 赎金信、15. 三数之和、18. 四数之和
一、454.四数相加II
解题代码C:
// 哈希表大小
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;
}
题目链接/文章讲解/视频讲解:
https://programmercarl.com/0454.%E5%9B%9B%E6%95%B0%E7%9B%B8%E5%8A%A0II.html
二、383. 赎金信
解题代码C:
bool canConstruct(char* ransomNote, char* magazine) {
// 定义哈希映射数组
int hashmap[26] = {0};
// 对magazine中字符计数
while (*magazine != '\0') hashmap[*magazine++ % 26]++;
// 遍历ransomNote,对应的字符自减,小于0说明该字符magazine没有或不足够表示
while (*ransomNote != '\0') hashmap[*ransomNote++ % 26]--;
// 如果数组中存在负数,说明ransomNote不能由magazine里面的字符构成
for (int i = 0; i < 26; i++) {
if (hashmap[i] < 0) return false;
}
return true;
}
题目链接/文章讲解/视频讲解:
https://programmercarl.com/0383.%E8%B5%8E%E9%87%91%E4%BF%A1.html
三、15. 三数之和
解题代码C:
//qsort辅助cmp函数
int cmp(const void* ptr1, const void* ptr2) {
return *((int*)ptr1) > *((int*)ptr2);
}
int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {
//开辟ans数组空间
int **ans = (int**)malloc(sizeof(int*) * 18000);
int ansTop = 0;
//若传入nums数组大小小于3,则需要返回数组大小为0
if(numsSize < 3) {
*returnSize = 0;
return ans;
}
//对nums数组进行排序
qsort(nums, numsSize, sizeof(int), cmp);
int i;
//用for循环遍历数组,结束条件为i < numsSize - 2(因为要预留左右指针的位置)
for(i = 0; i < numsSize - 2; i++) {
//若当前i指向元素>0,则代表left和right以及i的和大于0。直接break
if(nums[i] > 0)
break;
//去重:i > 0 && nums[i] == nums[i-1]
if(i > 0 && nums[i] == nums[i-1])
continue;
//定义左指针和右指针
int left = i + 1;
int right = numsSize - 1;
//当右指针比左指针大时进行循环
while(right > left) {
//求出三数之和
int sum = nums[right] + nums[left] + nums[i];
//若和小于0,则左指针+1(因为左指针右边的数比当前所指元素大)
if(sum < 0)
left++;
//若和大于0,则将右指针-1
else if(sum > 0)
right--;
//若和等于0
else {
//开辟一个大小为3的数组空间,存入nums[i], nums[left]和nums[right]
int* arr = (int*)malloc(sizeof(int) * 3);
arr[0] = nums[i];
arr[1] = nums[left];
arr[2] = nums[right];
//将开辟数组存入ans中
ans[ansTop++] = arr;
//去重
while(right > left && nums[right] == nums[right - 1])
right--;
while(left < right && nums[left] == nums[left + 1])
left++;
//更新左右指针
left++;
right--;
}
}
}
//设定返回的数组大小
*returnSize = ansTop;
*returnColumnSizes = (int*)malloc(sizeof(int) * ansTop);
int z;
for(z = 0; z < ansTop; z++) {
(*returnColumnSizes)[z] = 3;
}
return ans;
}
题目链接/文章讲解/视频讲解:
https://programmercarl.com/0015.%E4%B8%89%E6%95%B0%E4%B9%8B%E5%92%8C.html
四、18. 四数之和
解题代码C:
/* qsort */
static int cmp(const void* arg1, const void* arg2) {
int a = *(int *)arg1;
int b = *(int *)arg2;
return (a > b);
}
int** fourSum(int* nums, int numsSize, int target, int* returnSize, int** returnColumnSizes) {
/* 对nums数组进行排序 */
qsort(nums, numsSize, sizeof(int), cmp);
int **res = (int **)malloc(sizeof(int *) * 40000);
int index = 0;
/* k */
for (int k = 0; k < numsSize - 3; k++) { /* 第一级 */
/* k剪枝 */
if ((nums[k] > target) && (nums[k] >= 0)) {
break;
}
/* k去重 */
if ((k > 0) && (nums[k] == nums[k - 1])) {
continue;
}
/* i */
for (int i = k + 1; i < numsSize - 2; i++) { /* 第二级 */
/* i剪枝 */
if ((nums[k] + nums[i] > target) && (nums[i] >= 0)) {
break;
}
/* i去重 */
if ((i > (k + 1)) && (nums[i] == nums[i - 1])) {
continue;
}
/* left and right */
int left = i + 1;
int right = numsSize - 1;
while (left < right) {
/* 防止大数溢出 */
long long val = (long long)nums[k] + nums[i] + nums[left] + nums[right];
if (val > target) {
right--;
} else if (val < target) {
left++;
} else {
int *res_tmp = (int *)malloc(sizeof(int) * 4);
res_tmp[0] = nums[k];
res_tmp[1] = nums[i];
res_tmp[2] = nums[left];
res_tmp[3] = nums[right];
res[index++] = res_tmp;
/* right去重 */
while ((right > left) && (nums[right] == nums[right - 1])) {
right--;
}
/* left去重 */
while ((left < right) && (nums[left] == nums[left + 1])) {
left++;
}
/* 更新right与left */
left++, right--;
}
}
}
}
/* 返回值处理 */
*returnSize = index;
int *column = (int *)malloc(sizeof(int) * index);
for (int i = 0; i < index; i++) {
column[i] = 4;
}
*returnColumnSizes = column;
return res;
}
题目链接/文章讲解/视频讲解:
https://programmercarl.com/0018.%E5%9B%9B%E6%95%B0%E4%B9%8B%E5%92%8C.html