代码随想录训练营Day7|454. 四数相加 II, 383.赎金信, 15.三数之和, 18.四数之和

454. 四数相加 II

解题思路
  • 定义哈希表 map
  • 记录 nums1nums2 各个元素两两相加和及出现的次数,key=和value=和出现的次数
  • 记录 nums2nums3 各个元素两两相加和,如果map存在0 - (k + l)key,说明满足 nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0,由于不需要考虑重复元素,统计其出现的次数即可。
var fourSumCount = function(nums1, nums2, nums3, nums4) {
    let map = new Map();
    for (let i of nums1) {
        for (let j of nums2) {
            map.set(i+j, (map.get(i+j) || 0) + 1)
        }
    }
    let count = 0;
    for (let k of nums3) {
        for (let l of nums4) {
            count += map.get(0 - (k+l)) || 0
        }
    }
    return count;
};

383. 赎金信

解题思路
实现一
  • 哈希解法 - Map
  • 由于magazine 中的每个字母只能在 ransomNote 中使用一次,所以至少要统计magazine中各个字母出现的次数。
  • 遍历ransomNote,如果ransomNote中的字母不存在map中或者次数已用完,说明ransomNote所需要的字母 magazine 不能满足,返回 false;。
var canConstruct = function(ransomNote, magazine) {
    let map = new Map()
    for (let i of magazine){
        map.set(i,(map.get(i) || 0)+1)
    }
    for(let i of ransomNote){
        if (!map.get(i)) {
            return false;
        }
        map.set(i, map.get(i) - 1)
    }
    return true
};
实现二
  • 哈希解法 - Array
  • 由于题目说明 ransomNotemagazine 由小写英文字母组成,所以最大长度是可以确定为26的。
  • 在长度可以确定的情况下,由于使用 Map 的空间消耗要比 Array 大一些的,因此可以使用数组求解。
var canConstruct = function(ransomNote, magazine) {
    const strArr = new Array(26).fill(0);
    const base = "a".charCodeAt();
    for (let i of magazine) {
        strArr[i.charCodeAt() - base]++;
    }
    for (let i of ransomNote) {
        const index = i.charCodeAt() - base;
        if (!strArr[index]) {
            return false
        }
        strArr[index]--
    }
    return true
};

15. 三数之和

解题思路
  • 特殊判断,if (nums.length < 3) return false
  • nums 排序,从索引 i = 0 开始,使用双指针依次求和,收缩后续元素
  • left = i + 1right = nums.length - 1
  • if (arr[left] + arr[right] + arr[i] < 0) left++
  • if (arr[left] + arr[right] + arr[i] > 0) right--
  • else 保留一组结果值
难点

目标找出a + b + c = 0,且不可以包含重复的三元组,注意 [0,0,0,0]
a = nums[i], b = nums[left], c = nums[right]

  • 去重
    去重a:if (i > 0 && arr[i]==arr[i-1]) continue
    去重b:while(left < right && arr[left] === arr[left+1]) { left++ }
    去重c:while(left < right && arr[right] === arr[right-1]) { right-- }
var threeSum = function(nums) {
    if (nums.length < 3) {
        return []
    }
    let arr = nums.sort((a, b) => a - b)
    let left = 0;
    let right = arr.length - 1;
    let res = []
    for(let i = 0;i<arr.length;i++){
        // 如果排序后的第1个元素大于0,那么不可能凑成满足条件的三元组
        if(arr[i]>0) {
            return res
        }
        // 错误去重a方法,将会漏掉-1,-1,2 这种情况
        /*
            if (nums[i] == nums[i + 1]) {
                continue;
            }
        */
        if(i>0 && arr[i]==arr[i-1]) {
            continue
        }
        left = i+1
        right = arr.length - 1
        while(left < right) {
            if (arr[left]+arr[right] +arr[i] < 0){
                left++
            } else if(arr[left]+arr[right] +arr[i] > 0){
                right--
            } else {
                // 优先保存一组满足条件的元组
                res.push([arr[i],arr[left],arr[right]])
                // 去重逻辑应该放在找到一个三元组之后,对b 和 c去重
                while(left < right && arr[left] === arr[left+1]) {
                    left++
                }
                while(left < right && arr[right] === arr[right-1]) {
                    right--
                }
                left++
                right--
            }
        }
    }
    return res;
};

18. 四数之和

解题思路
  • 本题同15. 三数之和类似,看上去多了一层循环。
  • 注意目标值 target 不再是0,有可能是负数,比如排序后的数组arr = [-4, -3, -2, -1]target = -10,那么arr[0] > target,但是仍然存在满足条件的元组。
  • 第一层剪枝,满足 if(arr[i]>target && (arr[i] >= 0 || target >= 0)) { break },则说明不会出现满足条件的四元组。
  • 第一层去重,同15. 三数之和处理相同。
  • 第二层剪枝,if(arr[i] + arr[j] >target && arr[i] + arr[j] > 0) { break }
  • 第二层去重,if (arr[j] === arr[j-1] && j > i+1) { continue }
  • 剩余处理同15. 三数之和
var fourSum = function(nums, target) {
    let arr = nums.sort((a, b) => a - b);
    let res = [];
    let left = 0;
    let right = arr.length - 1;
    for (let i = 0; i < arr.length; i++) {
        if(arr[i]>target && (arr[i] >= 0 || target >= 0)) { // 一层剪枝
            break
        }
        if (arr[i] === arr[i-1] && i > 0) { // 一层去重
            continue
        }
        for (let j = i+1; j<arr.length; j++) {
            if(arr[i] + arr[j] >target && arr[i] + arr[j] > 0) { // 二层剪枝
                break
            }
            if (arr[j] === arr[j-1] && j > i+1) { 二层去重
                continue
            }
            left = j+1
            right = arr.length - 1
            while(left < right) {
                if (arr[left]+arr[right] +arr[i] + arr[j] < target){
                    left++
                } else if(arr[left]+arr[right] +arr[i] + arr[j] > target){
                    right--
                } else {
                    res.push([arr[i],arr[j],arr[left],arr[right]])
                    while(left < right && arr[left] === arr[left+1]) {
                        left++
                    }
                    while(left < right && arr[right] === arr[right-1]) {
                        right--
                    }
                    left++
                    right--
                }
            }
        }
    }
    return res;
};
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,233评论 6 495
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,357评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,831评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,313评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,417评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,470评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,482评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,265评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,708评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,997评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,176评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,827评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,503评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,150评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,391评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,034评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,063评论 2 352

推荐阅读更多精彩内容