Day7 四数相加 II

1.四数相加 II leetcode454

此题类似于昨天的力扣第一题,两数相加题。在map中先存入第一个数组,在遍历第二个数组,在map里面找 有没有减去第一个值的值存在,如果存在,即为找到了

此题是四数相加,所以可以先将两个数组相加,在将另外两个相加,最终实现四数相加

var fourSumCount = function (nums1, nums2, nums3, nums4) {
  // 四个数组,把它分为两个数组+两个数组
  // 将两个数组元素之和,和出现的次数,放到map中,key值为nums1[i]+nums2[j],value为次数
  let map = new Map();
  let count = 0;
  for (let i = 0; i < nums1.length; i++) {
    for (let j = 0; j < nums2.length; j++) {
      map.set(nums1[i] + nums2[j], (map.get(nums1[i] + nums2[j]) || 0) + 1)
    }
  }
  // 在map中寻找,用0减去第三个数组和第四个数组的和,如果找到,就将该次数累加起来,
  for (let m = 0; m < nums3.length; m++) {
    for (let n = 0; n < nums4.length; n++) {
      if (map.get(0 - (nums3[m] + nums4[n]))) {
        // 注意,累加次数。而不是每次加一
        count += map.get(0 - (nums3[m] + nums4[n]))
      }
    }
  }
  return count
}

2.赎金信 leetcode383

使用数组计数

var canConstruct = function (ransomNote, magazine) {
  let arr = new Array(26).fill(0);
  let base = 'a'.charCodeAt();
  for (let i = 0; i < magazine.length; i++) {
    arr[magazine[i].charCodeAt() - base]++
  }
  for (let j = 0; j < ransomNote.length; j++) {
    if (!arr[ransomNote[j].charCodeAt() - base]) {
      return false
    }
    // 注意:在arr中的一定要减
    arr[ransomNote[j].charCodeAt() - base]--
  }
  return true
}

3.三数之和 leetcode15

给定一个数组,返回所有和为 0 且不重复的三元组

这里说下双指针解法,这里还有一个地方需要注意的是:如何去重

首先是求三元数组之和,及a+b+c=0;首先确定三个数分别为什么

i,left,right分别为a,b,c三个数字,i是遍历的指针,left是i的下一位,right是数组的最后一个元素。

因为数组排序过,所以如果相加大于0,就将right向前移动,如果小于0,就将left向右移动

接下来是去重

a的去重,即nums[i]的去重。

如果使用nums[i]===nums[i+1], i+1指向的是left,这就变成了所组成的三元数组里不能有重复的元素

但是题目要求的是不重复的三元数组

所以使用nums[i]===nums[i-1],这样a就不会重复加入数组中

b和c的去重

当我们得到了想要的组合后,要进行bc去重

 

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

最终代码

var threeSum = function (nums) {
  const res = []
  // 先排序
  nums.sort((a, b) => a - b);
  for (let i = 0; i < nums.length; i++) {
    // 排序过,如果第一个数就大于0,就无法使其等于0
    if (nums[i] > 0) {
      return res
    }
    let left = i + 1;
    let right = nums.length - 1;
    // a去重
    if (nums[i] === nums[i - 1]) {
      continue
    }
    while (left < right) {
      let thresSum = nums[i] + nums[right] + nums[left]
      if (thresSum > 0) {
        right--
      } else if (thresSum < 0) {
        left++
      } else {
        res.push(nums[i], nums[left], nums[right]);
        // bc去重
        while (left < right && nums[left] === nums[left + 1]) {
          left++
        }
        while (left < right && nums[right] === nums[right - 1]) {
          right++
        }
        left++;
        right--;
      }
    }
  }
  return res
};

4.四数之和 leetcode18

跟三数之和类似,多了一层循环,但是圈复杂度有点高,可以进行函数提取降低复杂度

var fourSum = function (nums) {
  //接收结果
  let res = []
  //排序
  nums.sort((a, b) => a - b)
  for (let k = 0; k < nums.length - 3; k++) {
    // 跟三数之和相比,这里不能k>target就去掉,
    // 因为target可能是任意值,有可能是负值,如果nums[k]是负数,负数跟后面数相加,还是可能等于target
    // 如[-5,-1,-1,-1],target=-8 -5>-8
    if (nums[k] > target && (nums[k] >= 0 || target >= 0)) {
      break
    }
    // 对于a去重
    if (nums[k] === nums[k - 1] && k > 0) {
      continue
    }
    // 循环第二个数
    for (let i = k + 1; i < nums.length - 2; i++) {
      // nums[i] + nums[k]为一个整体
      if (nums[i] + nums[k] > target && (nums[i] + nums[k] >= 0 || target >= 0)) {
        break
      }
      // i必须大于k+1
      if (nums[i] === nums[i - 1] && i > k + 1) {
        continue
      }
      let left = i + 1;
      let right = nums.length - 1;
      while (left < right) {
        const sum = nums[k] + nums[i] + nums[left] + nums[right]
        if (sum > target) {
          right--
        } else if (sum < target) {
          left++
        } else {
          res.push([nums[k], nums[i], nums[left], nums[right]])
          // 对left和right进行去重
          while (left < right && nums[left] === nums[left + 1]) {
            left++
          }
          while (left < right && nums[right] === nums[right - 1]) {
            right--
          }
          // 移动指针
          left++;
          right--;
        }
      }

    }
  }
  return res

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值