三数之和(Swift实现)

84 阅读3分钟

题目如下:(leetcode 热题100)

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

注意: 答案中不可以包含重复的三元组。

对于这个题目,解决方法有很多种,但是相对简单的就是双指针,我们可以把这个题目看作是两数之和的升级版。

1.我们便利数组,这个是三数中的第一个A

2.我们用0 - A等于 B + C。

按照这个思路,我们来解决这个问题 首先我们考虑一下边界问题:

    if nums.count < 3 {return [[]]}

如果数组的长度大于等于3,我们就正常的遍历计算即可

在遍历之前,我们需要把数组进行一个排序,这个可以直接使用swift自带的排序。他的效率非常高,也为我们后续的筛选节省了很多时间

    let newSums = nums.sorted()
    var totalSum: [[Int]] = []

现在我们可以开始遍历了。这样的好处是我们在计算的时候指针的移动更加方便了。

我们使用两个指针,left和right,一个指在前面,一个指在末尾。 因为newSums是已经排序了的。那么我们就知道我们的指针该怎么移动了

比如left对应的值 + right对应的值大于我们需要的值,那说明我们需要把right指针往左移动,如果left对应的值 + right对应的值小于我们需要的值,说明我们需要left右移动,保证我们的结果跟他靠近直到等于。

这里我们写出我们的部分代码

    for i in newNums {
        if i > 0 && newNums[i] == newNums[i-1] {//如果这个值相同的话需要过滤掉,不然结果重复了
            continue
        }
        var left = i + 1 (因为之前的元素遍历过,所以要从当前元素的下一位开始遍历)
        var right = nums.count - 1
        while left < right {
            let sum = newSums[i] + newSums[left] + newSums[right]
            if sum > 0 {
                right -= 1
            } else if sum < 0 {
                left += 1
            } else {
                //这个地方需要考虑到去重,因为newNums的元素可能有好多过重复的,但是我们只需要第一个计算的值,其他的我们跳过,下面我们会讲解
            }
        }
    }

当然这么做还有个问题,我们如果数组的元素相同的话,我们需要考虑到过滤掉相同的数据带来的重复问题

   // 如果sum == 0 left += 1, right -= 1,左指针右移,右指针左移
   // 我们还需要考虑到左移右移之后 元素重复的问题,如果重复需要跳过,不然结果会重复
    totalSum.append(newSums[i] + newSums[left] + newSums[right])
    left += 1
    right -= 1
    while left < right && newSums[left] == newSums[left - 1] {
        left += 1
    }
    
    while left < right && newSums[right] == newSums[right + 1] {
        right -= 1
    }

上面差不多就是我们的整体代码

func threeSum(_ nums: [Int]) -> [[Int]] {
    if nums.count < 3 {return [[]]}
    
    let newSums = nums.sorted()
    var totalSums: [[Int]] = []
    
    for i in 0..<newSums.count {
        if i > 0 && newSums[i] == newSums[i-1] {
            continue
        }
        
        var left = i + 1
        var right = newSums.count - 1
        while left < right {

            let sum = newSums[i] + newSums[left] + newSums[right]

            if sum > 0 {

                right -= 1

            } else if sum < 0 {

                left += 1

            } else {

                totalSums.append([newSums[i], newSums[left], newSums[right]])
                left += 1
                right -= 1

                while** (left < right) && newSums[left] == newSums[left - 1] {
                    left += 1
                }

                while (left < right) && newSums[right] == newSums[right + 1] {
                    right -= 1
                }
            }
        }
    }
    
        return totalSums
    }