leetcode:15.3-nums,16.3-nums-closest

148 阅读2分钟

题目描述

15:给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
16:给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。

解题思路

首先是暴力法,时间复杂度为O(n3),我们想办法对3重循环进行优化。
在这里,我们先将题设的3数相加暂时更改为;两数相加。用我们常规的优化思路,使用空间换取时间,可以将一重循环替换成查询hash结构,从而将n^2的时间复杂度减少至n。

var twoNums = (nums, target) => {
    let hash = {};
    let result = [];
    for(let i = 0 ; i < target.length; i++){
        if(!hash[nums[i]]){
            result.push([nums[i], hash[nums[i]]);
        }else{
            hash[nums[i]] = target - nums[i];
        }
    }
    return result;
}

当我们重新来看3数相加时,就会发现一条优化的方向,努力减少循环的层数,固定一个数后,就是两数相加的问题,进而根据题目优化,在这一步步到最后,就得到了最优解,双指针法
先将数组进行排序,

  • 外层循环固定一个数后,剩余部分头尾分别置一指针
  • 计算和与target进行比较,之后移动指针(取决于大小排序)
  • 若得到值的则存入数组 第16题思路类似,唯一不同的是16可以再优化,得到0可直接退出等

代码

JS版

15:
var threeSum = function (nums) {
  let res = [];
  let nums_copy = nums.sort((a, b) => a - b);
  for (let i = 0; i < nums_copy.length - 2; i++) {
    let L = i + 1,
      R = nums_copy.length - 1;
    if (nums_copy[i] > 0)
      break;
    if (nums_copy[i] == nums_copy[i - 1])
      continue;
    while (L < R) {
      let target = nums_copy[i] + nums_copy[L] + nums_copy[R];
      if (target === 0) {
        res.push([nums_copy[i], nums_copy[L], nums_copy[R]]);
        while (nums_copy[L] == nums_copy[L + 1] && L < R) {
          L++;
        }
        while (nums_copy[R] == nums_copy[R - 1] && L < R) {
          R--;
        }
        L++;
        R--;
      } else if (target < 0) {
        L++;
      } else if (target > 0) {
        R--;
      }
    }
  }
  return res;
};

PY版

class Solution:
    def threeSum(self, nums: [int]) -> [[int]]:
        nums.sort()
        res, k = [], 0
        for k in range(len(nums) - 2):
            if nums[k] > 0: break # 1. because of j > i > k.
            if k > 0 and nums[k] == nums[k - 1]: continue # 2. skip the same `nums[k]`.
            i, j = k + 1, len(nums) - 1
            while i < j: # 3. double pointer
                s = nums[k] + nums[i] + nums[j]
                if s < 0:
                    i += 1
                    while i < j and nums[i] == nums[i - 1]: i += 1
                elif s > 0:
                    j -= 1
                    while i < j and nums[j] == nums[j + 1]: j -= 1
                else:
                    res.append([nums[k], nums[i], nums[j]])
                    i += 1
                    j -= 1
                    while i < j and nums[i] == nums[i - 1]: i += 1
                    while i < j and nums[j] == nums[j + 1]: j -= 1
        return res

时间复杂度

O(n2),