代码随想录算法训练营第7天|454.四数相加II |383. 赎金信 |15. 三数之和 |18. 四数之和
454.四数相加II
建议:本题是 使用map 巧妙解决的问题,好好体会一下 哈希法 如何提高程序执行效率,降低时间复杂度,当然使用哈希法 会提高空间复杂度,但一般来说我们都是舍空间 换时间, 工业开发也是这样。
题目链接/文章讲解/视频讲解:https://programmercarl.com/0454.%E5%9B%9B%E6%95%B0%E7%9B%B8%E5%8A%A0II.html
typedef struct HashTable
{
int key ;
int value;
UT_hash_handle hh;
}map;
int fourSumCount(int* nums1, int nums1Size, int* nums2, int nums2Size, int* nums3, int nums3Size, int* nums4, int nums4Size){
int i,j;
map *hash=NULL;
for(i=0;i<nums1Size;i++)
for(j=0;j<nums2Size;j++)
{
map *tem=(map*)malloc(sizeof(map));
int ikey=nums1[i]+nums2[j];
HASH_FIND_INT(hash,&ikey,tem);
if(tem==NULL)
{
map *tem=(map*)malloc(sizeof(map));
tem->key=ikey,tem->value=1;
HASH_ADD_INT(hash,key,tem);
}else
tem->value++;
}
int ans=0;
for(i=0;i<nums3Size;i++)
for(j=0;j<nums4Size;j++)
{
int c=0-(nums3[i]+nums4[j]);
map *tem=(map*)malloc(sizeof(map));
HASH_FIND_INT(hash,&c,tem);
if(tem!=NULL)
{
ans+=tem->value;
}
}
return ans;
--
}
总结
总的来说map的算法,跟昨天的两数之和比较接近。也是先把当前数,用HASH_FIND_INT(hash表,&要找的数,指针),有则次数++,若没有就放到hash表里面,下面34的双重循环继续找target-当前数的值,把符合次数的相加,最后return ans。
- 赎金信
建议:本题 和 242.有效的字母异位词 是一个思路 ,算是拓展题
题目链接/文章讲解:https://programmercarl.com/0383.%E8%B5%8E%E9%87%91%E4%BF%A1.html
bool canConstruct(char* ransomNote, char* magazine) {
int i;
int a[26]={0};
for(i=0;i<strlen(magazine);i++)
a[magazine[i]-'a']++;
for(i=0;i<strlen(ransomNote);i++)
a[ransomNote[i]-'a']--;
for(i=0;i<26;i++)
if(a[i]<0)
return false;
return true;
}
总结
有效的字母异位词 一个类型。都是哈希数组另放,然后范围大的样例数组先在哈希里++,范围小的–,发现负数就说明不匹配。
- 三数之和
建议:本题虽然和 两数之和 很像,也能用哈希法,但用哈希法会很麻烦,双指针法才是正解,可以先看视频理解一下 双指针法的思路,文章中讲解的,没问题 哈希法很麻烦。
题目链接/文章讲解/视频讲解:https://programmercarl.com/0015.%E4%B8%89%E6%95%B0%E4%B9%8B%E5%92%8C.html
/**
* Return an array of arrays of size *returnSize.
* The sizes of the arrays are returned as *returnColumnSizes array.
* Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
*/
int cmp_int(const void* e1, const void* e2)
{
//比较两个整型类型
return *(int*)e1 - *(int*)e2;
}
int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {
int i;
int **result=(int **)malloc(sizeof(int*)*100000);//定义一个动态二维数组,内存占题目要求最大
int resTop=0;//记录二维数组最多有多少个集合
if(numsSize<3)//去重
{
*returnSize=0;
return result;
}
qsort(nums,numsSize,sizeof(int),cmp_int);//调用快排函数
for(i=0;i<numsSize-2;i++)//numSize-2去重
{
if(nums[i]>0)
break;//去重
if(i>0&&nums[i]==nums[i-1])
continue;//剪枝(去重)
//双指针法
int left,right;
left=i+1;
right=numsSize-1;
while(left<right)
{
int sum=nums[i]+nums[left]+nums[right];
if(sum>0)
right--;
else if(sum<0)
left++;
else
{
int *arr=(int*)malloc(sizeof(int)*3);//定义一个临时的动态数组存结果
arr[0]=nums[i];
arr[1]=nums[left];
arr[2]=nums[right];
result[resTop++]=arr;//临时数组的数据放入最终的数组里面
while(right>left&&nums[left]==nums[left+1])
left++;//去重
while(right>left&&nums[right]==nums[right-1])
right--;//去重
left++;
right--;
}
}
}
*returnSize=resTop;//返回行数
*returnColumnSizes=(int*)malloc(sizeof(int)*resTop);
int z;
for(i=0;i<resTop;i++)
{
(*returnColumnSizes)[i]=3;//返回二维数组每行的列数
}
return result;
}
总结
qsort()重要的,里面的com是要自己判定,重点是去重。很重要这题,下次我尝试拍视频应该可以说清楚。
- 四数之和
建议: 要比较一下,本题和 454.四数相加II 的区别,为什么 454.四数相加II 会简单很多,这个想明白了,对本题理解就深刻了。 本题 思路整体和 三数之和一样的,都是双指针,但写的时候 有很多小细节,需要注意,建议先看视频。
题目链接/文章讲解/视频讲解:https://programmercarl.com/0018.%E5%9B%9B%E6%95%B0%E4%B9%8B%E5%92%8C.html
int comp(const void* a, const void* b) {
return *(int*)a - *(int*)b;
}
int** fourSum(int* nums, int numsSize, int target, int* returnSize, int** returnColumnSizes) {
int** quadruplets = malloc(sizeof(int*) * 1001);
*returnSize = 0;
*returnColumnSizes = malloc(sizeof(int) * 1001);
if (numsSize < 4) {
return quadruplets;
}
qsort(nums, numsSize, sizeof(int), comp);
int length = numsSize;
for (int i = 0; i < length - 3; i++) {
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
if ((long) nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) {
break;
}
if ((long) nums[i] + nums[length - 3] + nums[length - 2] + nums[length - 1] < target) {
continue;
}
for (int j = i + 1; j < length - 2; j++) {
if (j > i + 1 && nums[j] == nums[j - 1]) {
continue;
}
if ((long) nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) {
break;
}
if ((long) nums[i] + nums[j] + nums[length - 2] + nums[length - 1] < target) {
continue;
}
int left = j + 1, right = length - 1;
while (left < right) {
long sum = (long) nums[i] + nums[j] + nums[left] + nums[right];
if (sum == target) {
int* tmp = malloc(sizeof(int) * 4);
tmp[0] = nums[i], tmp[1] = nums[j], tmp[2] = nums[left], tmp[3] = nums[right];
(*returnColumnSizes)[(*returnSize)] = 4;
quadruplets[(*returnSize)++] = tmp;
while (left < right && nums[left] == nums[left + 1]) {
left++;
}
left++;
while (left < right && nums[right] == nums[right - 1]) {
right--;
}
right--;
} else if (sum < target) {
left++;
} else {
right--;
}
}
}
}
return quadruplets;
}
总结
与上题同理,就多了一个外层循环。