代码随想录-第七天

题一:四数相加

题目链接:四数相加
解题思路: 题目给出四个数组,要求在这个数组中分别取一个数使得nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0,返回满足此要求元组的个数,注意这里不要求去重,所以我们只管遍历即可,我首先想到先遍历num1和nums2,把这俩数之和放置一个map当中,在设置一个count记录目标元组个数,把num1+num2当key,把出现次数做value,然后再去遍历num2和num3,在我们之前设置过的数组中查找,此时key = 0 - (num3[k] + num4[I]),如果存在直接累加至count变量即可,根据以上要点此题可解。
解题代码:

var fourSumCount = function (nums1, nums2, nums3, nums4) {
    // 先算nums1 + nums2
    let tagMap = new Map();
    let count = 0;
    for (let i = 0; i < nums1.length; i++) {
        for (let j = 0; j < nums2.length; j++) {
            let key = nums1[i] + nums2[j];
            if (tagMap.has(key)) {
                let value = tagMap.get(key) + 1;
                tagMap.set(key, value);
            } else {
                tagMap.set(key, 1)
            }
        }
    }
    console.log(tagMap)
    for (let i = 0; i < nums3.length; i++) {
        for (let j = 0; j < nums4.length; j++) {
            let key = 0 - (nums3[i] + nums4[j]);
            if (tagMap.has(key)) {
                count += tagMap.get(key);
            }
        }
    }
    return count;

};

题二:赎金信

题目链接:赎金信
解题思路: 题目给出连个字符串,问第一个字符串是否可由第二个字符串的字母组成,且第二个字符串的每个字符只能用一次,我的思路是利用map解决,遍历第二个字符串,把字符当作key,出现次数作为value存入,再遍历第一个字符串,再遍历时,如果在我们设定的map中查找到了此字符的记录的话则将该键对应的键值-1,如果没有找到或者是次value===0,直接返回false。最后如果一切顺利则返回true。
解题代码:

var canConstruct = function (ransomNote, magazine) {
    let map_magz = new Map();
    for(let i = 0; i < magazine.length;i++){
        if(map_magz.has(magazine[i])){
            let value = map_magz.get(magazine[i]) + 1;
            map_magz.set(magazine[i],value)
        }else{
            map_magz.set(magazine[i],1)
        }
    }
    for (let i = 0; i < ransomNote.length; i++) {
        if (!map_magz.has(ransomNote[i]) || map_magz.get(ransomNote[i]) <= 0) {
            return false;
        } else {
            let value = map_magz.get(ransomNote[i]) - 1;
            map_magz.set(ransomNote[i],value)
            // console.log(map_magz)
        }
    }
    return true;
};

题三:三数之和

题目链接:三数之和
解题思路: 题目给定一个数组,要求出nums[i] + nums[j] + nums[k] = 0的时候的所有元组,且元组不能重复,这里就涉及到了一个去重的操作,一般会想到用哈希表来做,可是在这里用哈希去重的逻辑太复杂了(其实是我懒得看了),就不做解释,直接用卡哥推荐的三指针法,数组要先排序,方变我们后面的操作,遍历数组,初始时把数组的第一项设置为i=0,left=i+1,right=nums.length -1,这里的主要思想就是数组数值从下到大排列,我们可以根据这个特性来移动指针,如果三数之和大于0,right向左移动,如果三数之和小于0,left向右移动,这里还有一个特别重要的点就是去重的操作,先对于i,if(i>0&&nums[i] < nums[i-1) 则return,为什么是i-1而不是i+1呢,在这个场景之下,i-1的位置正是我们遍历过的,如果还算进去的话,一旦后面存在满足题目条件的情况,也就是三数相加等于0,这肯定是重复了的,而i+1的位置则是未遍历的元素,对于后面的情况我们不好判断。还有就是对left和right进行去重,在进入左右指针的移动循环时,left与left+1的值相等,left++,rigth与其左边的值相等,right–。
解题代码:

var threeSum = function (nums) {
    // 先排序
    nums = nums.sort((a, b) => a - b);
    let result = [];

    for (let i = 0; i < nums.length; i++) {
        if (nums[i] > 0) return result;
        // 对第一个数进行剪枝操作
        if (i !== 0 && nums[i] === nums[i - 1]) continue;
        let left = i + 1;
        let right = nums.length - 1;
        while (left < right) {
            let sum = nums[i] + nums[left] + nums[right];
            if (sum > 0) {
                right--;
            } else if (sum < 0) {
                left++
            } else {
                let temp = [];
                temp.push(nums[i]);
                temp.push(nums[left]);
                temp.push(nums[right]);
                result.push(temp);
                // 对left 和 right进行剪枝操作
                while (nums[left] === nums[left + 1]) {
                    left++;
                }
                while (nums[right] === nums[right - 1]) {
                    right--;
                }
                left++;
                right--;
            }
        }
    }
    return result;
};

4 四数之和

题目链接: 四数之和
解题思路: 跟三数之和类似,这里我们设置四个指针,k,i,left,right,循环遍历k、i,根据k、i移动left、right,初始时k=0,i=k+1, left = i+1, right= nums.length -1,去重剪枝操作与三数之和类似。
解题代码:

var fourSum = function (nums, target) {
    let result = [];
    nums = nums.sort((a, b) => a - b);
    if (nums.length < 4) return result;
    for (let k = 0; k < nums.length; k++) {
        if (nums[k] > target && nums[k] > 0) continue;
        if (k > 0 && nums[k] === nums[k - 1]) continue;
        for (let i = k + 1; i < nums.length; i++) {
            if (i > k + 1 && nums[i] === nums[i - 1]) continue;
            let left = i + 1;
            let right = nums.length - 1;
            while(left < right){
                let sum = nums[k] + nums[i] + nums[left] + nums[right];
                if(sum > target){
                    right--;
                }else if(sum < target){
                    left++;
                }else{
                    let temp = [];
                    temp.push(nums[k]);
                    temp.push(nums[i]);
                    temp.push(nums[left]);
                    temp.push(nums[right]);
                    result.push(temp);
                    while(nums[left] === nums[left+1]){
                        left++;
                    }
                    while(nums[right === nums[right-1]]){
                        right--;
                    }
                    left++;
                    right--;
                }
            }
        }
    }
    return result;
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值