代码随想录算法营DAY7 | 454.四数相加II 383. 赎金信 15. 三数之和 18. 四数之和

代码随想录算法营DAY7 | 454.四数相加II 383. 赎金信 15. 三数之和 18. 四数之和

454.四数相加II

题目链接: 454.四数相加II
思路:
1.根据两数相加的思路拓展,把A[i] + B[j] + C[k] + D[l] = 0看作(A[i] + B[j]) + (C[k] + D[l]) = 0。
2.两个for循环遍历A,B;先用map把A[i] + B[j] 的结果作为key存储,和出现的次数作为value
3.两个for循环遍历C,D;检查map里是否有(0-( C[k] + D[l] ))的元素,如果有,
代码:

var fourSumCount = function(nums1, nums2, nums3, nums4) {
    const map = new Map(); // 定义Map结构

    for (const i of nums1) { // 遍历nums1、nums2,这里i与j就代表着nums[i]、nums[j]
        for (const j of nums2) {
        	// 将i + j的和放入key,出现此处放入value,get()获取map的value值,出现就将其加入,未出现则加入0。
        	// +1用来保证第一次获取value时添加的就是1,第二次循环get()返回的是1,再+1就变为2,以此类推
            map.set(i + j, (map.get(i + j) || 0) + 1);
        }
    }

    let count = 0;

    for (const k of nums3) { // 遍历nums3、nums4,这里k与l就代表着nums[k]、nums[l]
        for (const l of nums4) {
            if (map.has(0 - (k + l))) { // 判断map中是否存在0 - (k + l) = i+ j
                count += (map.get(0 - (k + l)) || 0); // 如果存在就让count加上a+b的和出现的次数
            }
        }
    }

    return count;
};

问题:
这里的 map.set(i + j, (map.get(i + j) || 0) + 1)表达式是什么意思?
复杂度分析:
时间复杂度:
O(n^2)

383. 赎金信

题目链接: 383. 赎金信
思路:
1.因为全是小写字母,所以可以用数组映射,这里用map空间开销比较大,因为map要维护红黑树或者哈希表,而且还要做哈希函数,是费时的!数据量大的话就能体现出来差别了。 所以数组更加简单直接有效!
2.遍历magazine统计字母出现频率。
3.遍历ransomNote,若ransomNote里的字母在magazine里面没出现过就就直接返回false,若遍历完了没返回false,则可以返回true。

代码:

var canConstruct = function(ransomNote, magazine) {
    const strArr = new Array(26).fill(0),
        base = "a".charCodeAt();
    for(const s of magazine){
        strArr[s.charCodeAt() - base]++;
    }
    for(const s of ransomNote){
        const index = s.charCodeAt()-base;
        if(!strArr[index]) return false;
        strArr[index]--;
    }
    return true;
};

复杂度分析:
时间复杂度:O(n)

15. 三数之和

题目链接: 15. 三数之和
思路:

  1. 首先排序数组为非递减数组,然后定义指针i指向下标0,指针left指向i + 1,指针right指向末尾元素
  2. 要完成的任务变为nums[i] + nums[left] + nums[right] = 0
  3. for循环让i遍历数组,如果nums[i] + nums[left] + nums[right] >
    0说明,三数之和过大了,right指针要向左移动,让三数之和变小一点;
  4. 如果nums[i] + nums[left] + nums[right] <
    0说明,三数之和过小了,left指针要向右移动,让三数之和变大一点。
  5. 直到left与right相遇,此时i进行下一次移动,left回到当前的i + 1位置,重复寻找操作。
  6. 找到的元组存在重复的可能。因此还要进行去重,去重操作要完成的是不能有重复的三元组,但三元组内的元素是可以重复的,要判断的是nums[i]与nums[i- 1]是否重复,这样才能避免将三元组内的重复元素也给排除了这一问题

代码:

var threeSum = function(nums) {
    const res = [], len = nums.length
    // 将数组排序
    nums.sort((a, b) => a - b)
    for (let i = 0; i < len; i++) {
        let l = i + 1, r = len - 1, iNum = nums[i]
        // 数组排过序,如果第一个数大于0直接返回res
        if (iNum > 0) return res
        // 去重
        if (iNum == nums[i - 1]) continue
        while(l < r) {
            let lNum = nums[l], rNum = nums[r], threeSum = iNum + lNum + rNum
            // 三数之和小于0,则左指针向右移动
            if (threeSum < 0) l++ 
            else if (threeSum > 0) r--
            else {
                res.push([iNum, lNum, rNum])
                // 去重
                while(l < r && nums[l] == nums[l + 1]){
                    l++
                }
                while(l < r && nums[r] == nums[r - 1]) {
                    r--
                }
                l++
                r--
            }
        }
    }
    return res
};

18. 四数之和

题目链接: 18. 四数之和
思路:
整体思路与三数之和一样,不同之处在于要比三数之和多处理一次,两层for循环找到两个值,然后left、right指针遍历找到剩下两个值。

代码:

var fourSum = function(nums, target) {
    const len = nums.length;
    
    if(len < 4) return []; // 数组长度小于4,直接返回
    nums.sort((a, b) => a - b); // 排序数组
    const res = [];

    for(let i = 0; i < len - 3; i++) { // 第一次缩小范围
        if(i > 0 && nums[i] === nums[i - 1]) continue; // 去重
        for(let j = i + 1; j < len - 2; j++) { // 第二次缩小范围
            if(j > i + 1 && nums[j] === nums[j - 1]) continue; // 去重
            
            let left = j + 1let right = len - 1;
                
            while (left < right) {
                const sum = nums[i] + nums[j] + nums[left] + nums[right];
                if(sum < target) { // 四数之和小于target,移动left指针寻找更大的数
                    left++;
                    continue;
                } else if (sum > target){ // 四数之和大于target,移动right指针寻找更小的数
					right--;
                    continue;
				} else {
					res.push([nums[i], nums[j], nums[left], nums[right]]); // 向res中插入结果
					// 去重
                	while (left < right && nums[left] === nums[left + 1]) left++;
                	while (left < right && nums[right] === nums[right - 1]) right--;

                	left++; // 插入成功后继续移动left寻找下一个的四数之和
                	right--; // 插入成功后继续移动left寻找下一个的四数之和
				} 
            }
        }
    }
    return res;
};

感想总结

js基础还需要巩固,学完js估计还得回来再刷一遍555

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值