leetcode(15. 三数之和)

505 阅读1分钟

image.png

思路:

其实最简单的思路就是暴力查找,三数之和,用三层循环去找,简单,但是时间复杂度为 n³ ,跑不通,故需要降低时间复杂度,于是乎便有了,排序+双指针解法

方法一:暴力查找

for(let i=0;...){
 for(let j=i+1;...){
  for(let t=j+1;...){
    if(nums[i]+nums[j]+nums[t] == 0){
       a.push(nums[i],nums[j],nums[t])
       res.push(a)
    }
  }
 }
}
return res

时间复杂度:O(n³)

很明显,这个算法确实不算最优解,故需要优化成方法二

方法二:排序+双指针(我觉得也可以说是三指针?)

思路:

  1. 特殊判断:if (nums.length) < 3,直接返回空数组(不符合题意)
  2. 将数组进行升序排序
  3. 如果数组的第一个数大于0,后面的数经过排序后也会大于0,故三数之和不可能等于0,直接返回空数组(不符合题意)
  4. 设置三个指针,第一个为数组最左的元素 i ,第二个为 i 指针右边的 left ,第三个为指向数组末端的 right
  5. 当 i>0 且 nums[i]==nums[i-1] 跳过此次循环,因为在上一次的循环中,已经把含有 nums[i] 这个数字的情况给包含进答案了,故不跳过的话相当于再来一次,答案会有重复元素
  6. 当 left《right 时循环计算 sum=nums[i]+nums[left]+nums[right] 并且按照如下规则将 left 和 right 指针进行移动
  • 当 sum == 0 时,将这个组合给记录在答案中,并且将 left 指针向后移动,跳过所有重复的 nums[left] ,right 指针同理向前移动,跳过所有重复的 nums[right]
  • 当 sum < 0 时,证明 nums[left] 不够大,故将 left 向后移动,并跳过重复元素
  • 当 sum > 0 时,证明 nums[right] 太大了,故将 right 向前移动,并跳过重复元素
var threeSum = function (nums) {
    let len = nums.length
    let res = []
    if (len < 3) return []
    nums = nums.sort((a, b) => a - b)
    if (nums[0] > 0) return []
    let left, right
    for (let i = 0; i < len - 1; i++) {
        left = i + 1
        right = len - 1
        if (i > 0 && nums[i] == nums[i-1]) continue
        while (left < right) {
            let a = []
            if (nums[i] + nums[left] + nums[right] == 0) {
                a.push(nums[i],nums[left],nums[right])
                res.push(a)
                while (left < right && nums[left] == nums[left + 1]) {
                    left++
                }
                while (left < right && nums[right] == nums[right - 1]) {
                    right--
                }
                left++
                right--
            } else if (nums[i] + nums[left] + nums[right] < 0) {
                left++
                while(left < right && nums[left] == nums[left-1]) left++
            } else {
                right--
                while(left < right && nums[right] == nums[right-1]) right--
            }
        }
    }
    return res
};

时间复杂度: O(N²)