Leetcode 454.四数相加II

题目:454.四数相加II

初始思路

四个数组求和,可以参考242.有效的字母异位词,四个数组两两分组。

代码

  1. var fourSumCount = function (nums1, nums2, nums3, nums4) {
  2. // key放nums和nums2两数之和,value放两数之和出现的次数。
  3. const map = new Map()
  4. let count = 0
  5. // 遍历nums1和nums2数组,统计两个数组元素之和,和出现的次数,放到map中。
  6. for (let n1 of nums1) {
  7. for (let n2 of nums2) {
  8. const sum1 = n1 + n2
  9. if (map.has(sum1)) {
  10. map.set(sum1, map.get(sum1) + 1)
  11. } else {
  12. map.set(sum1, 1)
  13. }
  14. }
  15. }
  16. // 在遍历nums3和nums4数组,找到如果 0-(n3+n4) 在map中出现过的话,就用count把map中key对应的value也就是出现次数统计出来。
  17. for (let n3 of nums3) {
  18. for (let n4 of nums4) {
  19. const sum2 = - n3 - n4
  20. if (map.has(sum2)) {
  21. count += map.get(sum2)
  22. }
  23. }
  24. }
  25. return count
  26. };

感想

  1. 思路参考242.有效的字母异位词
  2. 要注意map的key和value都存放的是什么,key放nums和nums2两数之和,value放两数之和出现的次数。
  3. 在遍历的过程中,如果这个和没出现过,次数就设置为1,如果出现过就获取这个和的value值。
  4. 在遍历nums3和nums4的时候,直接找-(n3+n4)出现的次数即可。

Leetcode 383.赎金信

题目:383.赎金信

初始思路

思路参考242.有效的字母异位词。还是先记录magazine中的字符,然后再ransomNote中对比查找。

代码

  1. var canConstruct = function (ransomNote, magazine) {
  2. if (ransomNote.length > magazine.length) return false
  3. const resSet = new Array(26).fill(0)
  4. const base = 'a'.charCodeAt()
  5. for (let s of magazine) {
  6. resSet[s.charCodeAt() - base]++
  7. }
  8. for (let s of ransomNote) {
  9. // 如果ransomNote中出现了magazine不存在的字符
  10. if (!resSet[s.charCodeAt() - base]) return false
  11. // 使用过就减1,因为magazine中的字符不能出现多次
  12. resSet[s.charCodeAt() - base]--
  13. }
  14. return true
  15. };

感想

  1. 因为题目说了只有小写字母,所以用数组更方便。
  2. 要熟练掌握这种题目的写法。

Leetcode 15.三数之和

题目:15.三数之和

初始思路

没什么思路,看到题解才理解一点,但是res数组去重还是有点难理解。

代码

  1. var threeSum = function (nums) {
  2. const res = []
  3. const len = nums.length
  4. if (nums == null || len < 3) return res
  5. // 数组排序
  6. nums.sort((a, b) => a - b)
  7. for (let i = 0; i < len; i++) {
  8. let left = i + 1, right = len - 1
  9. // 如果 nums[i]大于 0,则三数之和必然无法等于 0,结束循环
  10. if (nums[i] > 0) break
  11. // 如果 nums[i] = nums[i−1],则说明该数字重复,会导致结果重复,所以应该跳过
  12. if (i > 0 && nums[i] === nums[i - 1]) continue
  13. while (left < right) {
  14. let sum = nums[i] + nums[left] + nums[right]
  15. if (sum < 0) left++
  16. else if (sum > 0) right--
  17. else {
  18. res.push([nums[i], nums[left], nums[right]])
  19. // 当 sum = 0 时,nums[L] == nums[L+1] 则会导致结果重复,应该跳过,L++
  20. while (left < right && nums[left] === nums[left + 1]) {
  21. left++
  22. }
  23. // 当 sum = 0 时,nums[R] == nums[R−1] 则会导致结果重复,应该跳过,R−−
  24. while (left < right && nums[right] === nums[right - 1]) {
  25. right--
  26. }
  27. left++
  28. right--
  29. }
  30. }
  31. }
  32. return res
  33. };

感想

  1. 使用双指针法,题解:https://leetcode.cn/problems/3sum/solution/hua-jie-suan-fa-15-san-shu-zhi-he-by-guanpengchn/
  2. 三元组需要做去重操作。这个很细节,贴上代码随想录的截图。
  3. image.png
  4. 时间复杂度:O(n2),从O(n3)降了一阶。

Leetcode 18.四数之和

题目:18.四数之和

初始思路

和三数之和思路类似,需要再套一层for循环

代码

  1. var fourSum = function (nums, target) {
  2. const res = []
  3. const len = nums.length
  4. if (nums == null || len < 4) return res
  5. // 数组排序
  6. nums.sort((a, b) => a - b)
  7. for (let i = 0; i < len; i++){
  8. // 如果 nums[i] = nums[i−1],则说明该数字重复,会导致结果重复,所以应该跳过
  9. if (i > 0 && nums[i] === nums[i - 1]) continue
  10. for (let j = i + 1; j < len - 2; j++){
  11. // 去重
  12. if (j > i + 1 && nums[j] === nums[j - 1]) continue
  13. let left = j + 1, right = len - 1
  14. while (left < right) {
  15. let sum = nums[i] + nums[j] + nums[left] + nums[right]
  16. if (sum < target) {
  17. left++
  18. continue
  19. }
  20. if (sum > target) {
  21. right--
  22. continue
  23. }
  24. res.push([nums[i], nums[j], nums[left], nums[right]])
  25. while (left < right && nums[left] === nums[left + 1]) {
  26. left++
  27. }
  28. while (left < right && nums[right] === nums[right - 1]) {
  29. right--
  30. }
  31. left++
  32. right--
  33. }
  34. }
  35. }
  36. return res
  37. };

感想

  1. 好难写,好崩溃。但是思路跟上一题还是一样的。
  2. 多练练吧,今天有点怠惰了。
  3. 时间复杂度:O(n3),从O(n4)降了一阶。