[leetcode]双指针题:Three sum

three sum

考虑三数之和,主要的考点在于:

  • 三数是否意味着需要设置三个变量?
  • 如何保证结果的去重?

针对第一点,这其实是指针题很喜欢的场景,因为对于新手可能一下子思路很直,单其实一般如果几个变量之间存在一定的关系,都要采取化简得形式,毕竟变量越少处理的时候就会越简洁。
针对第二点,其实是这题的一个重点,我第一次的想法也是判断一下数组里面如果存在就不继续添加这种线性的思维。其实应该判断,如果是重复就不应该继续走下面的寻找过程。

解题思路:
其实不难,核心思想就是将3sum分解为『1 Sum + 2 Sum』,在对数组进行排序后,挑出第一个元素,然后在剩下的元素中利用首尾指针进行寻找。

解题的代码:
一般代码:

class Solution:
    """
    @param numbers: Give an array numbers of n integer
    @return: Find all unique triplets in the array which gives the sum of zero.
    """
    def threeSum(self, numbers):
        # write your code here
        numbers.sort()
        len_num=len(numbers)
        result=[]
        for i in range(len_num):
            if i>0 and numbers[i]==numbers[i-1]:
                continue
            temp=numbers[i]
            twosum=0-temp
            l=i+1
            r=len_num-1
            while l<r:
                two_temp=numbers[l]+numbers[r]
                if two_temp==twosum:
                    result.append([temp,numbers[l],numbers[r]])
                    l+=1
                    r-=1
                    while r>0 and numbers[r]==numbers[r+1]:
                        r-=1
                    while l<len_num and numbers[l]==numbers[l-1]:
                        l+=1
                elif two_temp>twosum:
                    r-=1
                else:
                    l+=1
        return result

leetcode上最快的代码:
跟普通做法不一样的地方在于:

  • 用hash 表来表示去重后的序列,省掉了去重导致移动的判断。
  • 只要遍历数组的其中一半就可以了。
  • 最难的地方引入了如下的公式,进一步缩减了搜索范围:
    -a - b = c <= keys[-1] >>>> b >= -keys[-1] - a
    b>>> a + 2b < a + b + c = 0 >>>> b < -a/2
from bisect import bisect_left, bisect_right

class Solution(object):
    def threeSum(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        m = {}
        result = []
        positive_keys = []
        negative_keys = []
        for n in nums:
            if n in m:
                m[n] += 1
            else:
                m[n] = 1

        if 0 in m and m[0] >=3:
            result.append([0, 0, 0])

        keys = list(m.keys())
        keys.sort()
        keys_num = len(keys)

        if keys_num == 0:
            return []

        end = bisect_left(keys, 0) # a < 0
        # begin = bisect_left(keys, -keys[-1]*2) # when b == c, a + b + c = a + 2c <= a + 2*max_c;
        # print begin
        # print keys[begin]
        for i in range(0, end):
            a = keys[i]

            #a == b
            if a != 0 and m[a] >= 2 and -2*a in m:
                result.append([a, a, -2*a])

            # -a - b = c <= keys[-1] >>>> b >= -keys[-1] - a
            min_b = -keys[-1] - a
            # b<c >>>> a + 2b < a + b + c = 0 >>>> b < -a/2
            max_b = -a/2

            b_begin = max(i + 1, bisect_left(keys, min_b))
            b_end = bisect_right(keys, max_b)
            for j in range(b_begin, b_end):
                b = keys[j]
                c = -a-b
                if c in m:
                    if b > c:
                        continue
                    #b<c or b==c
                    if b < c or m[b] >=2:
                        result.append([a, b, c])
        return result 

猜你喜欢

转载自blog.csdn.net/qq_34661230/article/details/85471246
今日推荐