【代码随想录算法训练营第七天 | 454.四数相加II 383. 赎金信 15. 三数之和 18. 四数之和 总结 】

四数相加2

leetcode

代码随想录

  • 前提
    • 不用考虑每个数组使用重复的元素
  • 要点
    • A+B+C+D = (A+B) + (C+D) -> -(A+B) = C+D,相当于查找CD之和中有无等于AB之和的负数。可以使用哈希查找
    • 数据范围大,而且需要记录重复的AB和数量,考虑使用unordered_map
    • key存储AB和,value存储重复的AB和数量
typedef struct {
    int key;
    int value;
    UT_hash_handle hh;
}map;

map *hashMap = NULL;

map* hashMapFind(int key){
    map* tmp = NULL;
    HASH_FIND_INT(hashMap, &key, tmp);
    return tmp;
}

void hashMapAdd(int key, int value){ 
    if (hashMapFind(key) == NULL){
        map* tmp = malloc(sizeof(map));
        tmp -> key = key;
        HASH_ADD_INT(hashMap, key, tmp);
        tmp -> value = value;
    }
}

void hashMapPrint(){
    map* cur = NULL;
    for (cur = hashMap; cur != NULL; cur = cur -> hh.next){
        printf("key:%d, value:%d\n", cur -> key, cur -> value);
    }
}

void hashMapCleanUp(){
    map *cur, *tmp;

    HASH_ITER(hh, hashMap, cur, tmp){
        HASH_DEL(hashMap, cur);
        free(cur);
    }
}

int fourSumCount(int* nums1, int nums1Size, int* nums2, int nums2Size, int* nums3, int nums3Size, int* nums4, int nums4Size){
    hashMap = NULL;
    map *hashMapRec = NULL;
    int cnt = 0;

    for (int i = 0; i < nums1Size; i++){
        for (int j = 0; j < nums2Size; j++){
            int sum1 = nums1[i] + nums2[j];
            hashMapRec = hashMapFind(sum1);
            if (hashMapRec == NULL){
                hashMapAdd(sum1, 1);
            }
            else {
                hashMapRec -> value++;
            }
        }
    }

    hashMapPrint();

    for (int i = 0; i < nums3Size; i++){
        for (int j = 0; j < nums4Size; j++){
            int sum2 = nums3[i] + nums4[j];
            hashMapRec = hashMapFind(-sum2);
            if (hashMapRec != NULL){
                cnt = cnt + hashMapRec -> value;
            }
        }
    }

    hashMapCleanUp();

    return cnt;
}

赎金信

leetcode

代码随想录

  • 前提
    • ransomNotemagazine 由小写英文字母组成
    • magazine 中的每个字符只能在 ransomNote 中使用一次
  • 要点
    • 可以使用数组哈希查找
bool canConstruct(char* ransomNote, char* magazine) {
    int arrayRec[26] = {0};
    int sizeR = strlen(ransomNote);
    int sizeM = strlen(magazine);

    if (sizeM < sizeR){
        return false;
    }

    for (int i = 0; i < sizeM; i++){
        arrayRec[magazine[i] - 'a']++;
    }

    for (int i = 0; i < sizeR; i++){
        if (arrayRec[ransomNote[i] - 'a'] > 0){
            arrayRec[ransomNote[i] - 'a']--;
        }
        else {
            return false;
        }
    }

    return true;
}

三数之和

leetcode

代码随想录

  • 前提

    • i != ji != kj != k
    • 答案中不可以包含重复的三元组
  • 要点

    • 先将数组排序

    • 双指针法:在for循环里(i从0开始)使用快慢指针leftright

    • 使a=nums[i]b=nums[left]c=nums[right],求a+b+c=0

    • 在第i层循环,while(left < right)如何移动指针

      一次移动一格

      • 剪枝
        • (a+b) +c > 0时,左移right
        • (a+b) +c < 0时,右移left
      • (a+b) +c = 0时,更新leftright

      15.三数之和

    • abc如何去重

      • nums[i] = nums[i-1]时,会重复上一轮的操作,i向后移动
      • nums[left+1] = nums[left]时,会重复上轮的操作,left++
      • nums[right-1] = nums[right]时,会重复上一轮操作,right--
/**
 * 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().
 */
 #define MAX_SIZE 18000

/* qsort辅助cmp函数 */
int cmp(const void *a, const void *b){
    return *(int*)a - *(int*)b;
}

int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {
    int **returnArray = malloc(sizeof(int*) * MAX_SIZE);
    int cnt = 0;

    if (numsSize < 3){
        *returnSize = 0;
        return returnArray;
    }

    qsort(nums, numsSize, sizeof(int), cmp);

    for (int i = 0; i < numsSize - 2; i++){
        if (nums[i] > 0){
            break;
        }

        //i去重
        if (i > 0 && nums[i] == nums[i-1]){
            continue;
        }

        int left = i + 1;
        int right = numsSize - 1;

        while (left < right){
            int sum = nums[i] + nums[left] + nums[right];

            if (sum < 0){
                left ++;
            }
            else if (sum > 0){
                right --;
            }
            else {
                returnArray[cnt] = malloc(sizeof(int)*3);
                returnArray[cnt][0] = nums[i];
                returnArray[cnt][1] = nums[left];
                returnArray[cnt][2] = nums[right];
                cnt++;

                //left、right去重
                while (left < right && nums[left] == nums[left+1]){
                    left++;
                }
                while (left < right && nums[right] == nums[right-1]){
                    right--;
                }

                //更新left、right
                left++;
                right--;
            }
        }

    }

    *returnSize = cnt;
    *returnColumnSizes = malloc(sizeof(int)*cnt);
    for (int i = 0; i < cnt; i++){
        (*returnColumnSizes)[i] = 3;
    }

    return returnArray;
}

四数之和

leetcode

代码随想录

  • 前提
    • abcd 互不相同
    • 答案中不可以包含重复的四元组
  • 要点
    • 解题思路参考三数之和
    • 去重部分相同,剪枝部分不同:
      • target可能是负数,此时不能用nums[k] > target剪枝,例如target=-4, nums=[-3,-1,0,1]
      • 使用nums[k]*4 > target
    • 加法的中间过程有可能数据溢出,将加数强转为long int解决
/**
 * 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().
 */
 #define MAX_SIZE 18000

 int cmp(const void *a, const void *b){
    return *(int*)a - *(int*)b;
 }

int** fourSum(int* nums, int numsSize, int target, int* returnSize, int** returnColumnSizes) {
    int **returnArray = malloc(sizeof(int*) * MAX_SIZE);
    int cnt = 0;

    if (numsSize < 4){
        *returnSize = 0;
        return returnArray;
    }

    qsort(nums, numsSize, sizeof(int), cmp);

    for (int k = 0; k < numsSize-3; k++){
        if (nums[k] > 0 && nums[k] > target){
            break;
        }

        if (k > 0 && nums[k] == nums[k-1]){
            continue;
        }

        for (int i = k+1; i < numsSize-2; i++){
            if (nums[i] > 0 && ((long int)nums[k] + (long int)nums[i]) > target){
                break;
            }

            if (i > k+1 && nums[i] == nums[i-1]){
                continue;
            }

            int left = i+1;
            int right = numsSize-1;
            while (left < right){
                long int sum = (long int)nums[k] + (long int)nums[i] + (long int)nums[left] + (long int)nums[right];

                if (sum < target){
                    left++;
                }
                else if (sum > target){
                    right--;
                }
                else {
                    returnArray[cnt] = malloc(sizeof(int) * 4);
                    returnArray[cnt][0] = nums[k];
                    returnArray[cnt][1] = nums[i];
                    returnArray[cnt][2] = nums[left];
                    returnArray[cnt][3] = nums[right];
                    cnt++;

                    while (left < right && nums[left+1] == nums[left]){
                        left++;
                    }
                    while (left < right && nums[right-1] == nums[right]){
                        right--;
                    }

                    left++;
                    right--;
                }
            }
        }
    }

    *returnSize = cnt;
    *returnColumnSizes = malloc(sizeof(int)*cnt);
    for (int i = 0; i < cnt; i++){
        (*returnColumnSizes)[i] = 4;
    }

    return returnArray;
}

总结

  • 解题思路
    • 要不要用哈希表
    • 选什么哈希结构
    • 哈希结构存什么,怎么映射,怎么用
  • 有时用双指针法更简便
  • 关注去重和剪枝
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
代码随想录算法训练营是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第14天的训练营中,讲解了二叉树的理论基础、递归遍历、迭代遍历和统一遍历的内容。此外,在讨论中还分享了相关的博客文章和配图,帮助学员更好地理解和掌握二叉树的遍历方法。 训练营还提供了每日的讨论知识点,例如在第15天的讨论中,介绍了层序遍历的方法和使用队列来模拟一层一层遍历的效果。在第16天的讨论中,重点讨论了如何进行调试(debug)的方法,认为掌握调试技巧可以帮助学员更好地解决问题和写出正确的算法代码。 总之,代码随想录算法训练营是一个提供优质学习和讨论环境的平台,可以帮助学员系统地学习算法知识,并提供了丰富的讨论内容和刷题建议来提高算法编程能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [代码随想录算法训练营每日精华](https://blog.csdn.net/weixin_38556197/article/details/128462133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值