【刷题日记】三数之和

暴力解题:

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        total_len = len(nums)
        total_list = []
        if total_len < 3:
            return total_list
        for a_num in range(total_len-2):
            for b_num in range(a_num+1, total_len-1):
                if -nums[a_num]-nums[b_num] in nums[b_num+1:total_len]:
                    tmp_list = sorted([nums[a_num],nums[b_num],-nums[a_num]-nums[b_num]])
                    if tmp_list not in total_list:
                        total_list.append(tmp_list)
        return total_list

但这种写法存在时间复杂度太高的问题,超出时间限制

思考优化方式,想不出来。。偷看一眼题解,哦哦,原来是双指针,按照题解的思路写了一下:

1.先把数据排序,排序的作用就是方便后续双指针的做法

2.双指针,这里使用左指针——指向当前数字的下一个数字,从左向右移动,右指针——指向尾端,从右向左移动。因为前面排序过,那么前面的数字一定是小于等于后面的数字的,即左指针指向的数值永远小于等于右指针指向的数值。

 那么,在计算的时候,比如当前的指针情况 -4 + -1 + 2 = -3,这种情况下是小于0的,那么我们移动的指针肯定是 左指针,因为右指针这边的数字再去减小肯定不合理啊,左指针移动才有可能让总和增大,可以预见,当i指向第一个数的时候,直到左右指针相遇的时候,两者相加都不会等于0,于是下一次循环,我们将i移动到下一个位置。

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        total_len = len(nums)
        total_list = []
        if total_len < 3:
            return total_list
        sorted_nums = sorted(nums)
        for i in range(total_len):
            if i > 0 and sorted_nums[i] == sorted_nums[i-1]:
                continue 
            l_num = i + 1
            r_num = total_len - 1
            while l_num < r_num:

                sums = sorted_nums[l_num] + sorted_nums[r_num] + sorted_nums[i]
                if sums == 0:
                    tmp_list = sorted([sorted_nums[i],sorted_nums[l_num],sorted_nums[r_num]])
                    if tmp_list not in total_list:
                        total_list.append(tmp_list)
                    l_num += 1
                    r_num -= 1
                elif sums > 0:
                    r_num -= 1              
                else:
                    l_num += 1
        return total_list

这样写其实还是有重复计算,左右指针移动的时候还可以进行判断是不是跟上一次数字一样,一旦有重复,就多移动,直到指针☞的值与上次的不同:

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        total_len = len(nums)
        total_list = []
        if total_len < 3:
            return total_list
        sorted_nums = sorted(nums)
        for i in range(total_len):
            if i > 0 and sorted_nums[i] == sorted_nums[i-1]:
                continue 
            l_num = i + 1
            r_num = total_len - 1
            while l_num < r_num:

                sums = sorted_nums[l_num] + sorted_nums[r_num] + sorted_nums[i]
                if sums == 0:
                    total_list.append([sorted_nums[l_num], sorted_nums[r_num], sorted_nums[i]])
                    while l_num + 1 < r_num and sorted_nums[l_num] == sorted_nums[l_num + 1]: 
                        l_num += 1
                    while l_num + 1 < r_num and sorted_nums[r_num] == sorted_nums[r_num - 1]: 
                        r_num -= 1                  
                    l_num += 1
                    r_num -= 1
                elif sums > 0:
                    while l_num + 1 < r_num and sorted_nums[r_num] == sorted_nums[r_num - 1]: 
                        r_num -= 1 
                    r_num -= 1              
                else:
                    while l_num + 1 < r_num and sorted_nums[l_num] == sorted_nums[l_num + 1]: 
                        l_num += 1
                    l_num += 1
        return total_list

这样写,圈复杂度比较高,代码也存在重复率,可以把里面while判断提出来做单独的函数,这样代码上看就简洁很多,当然这里就不属于算法的范畴了:

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        total_len = len(nums)
        total_list = []
        if total_len < 3:
            return total_list
        sorted_nums = sorted(nums)
        for i in range(total_len):
            if i > 0 and sorted_nums[i] == sorted_nums[i-1]:
                continue 
            l_num = i + 1
            r_num = total_len - 1
            while l_num < r_num:

                sums = sorted_nums[l_num] + sorted_nums[r_num] + sorted_nums[i]
                if sums == 0:
                    total_list.append([sorted_nums[l_num], sorted_nums[r_num], sorted_nums[i]])
                    l_num = self.move_left_num(l_num, r_num, sorted_nums)        
                    r_num = self.move_right_num(l_num, r_num, sorted_nums)
                elif sums > 0:
                    r_num = self.move_right_num(l_num, r_num, sorted_nums)             
                else:
                    l_num = self.move_left_num(l_num, r_num, sorted_nums)        
        return total_list

    def move_left_num(self, l_num, r_num, sorted_nums):
        while l_num + 1 < r_num and sorted_nums[l_num] == sorted_nums[l_num + 1]: 
            l_num += 1
        l_num += 1
        return l_num

    def move_right_num(self, l_num, r_num, sorted_nums):
        while l_num + 1 < r_num and sorted_nums[r_num] == sorted_nums[r_num - 1]: 
            r_num -= 1 
        r_num -= 1
        return r_num

能不能再快一点?

经过排序以后,数字是从小到大排序的,那么如果当前位置的值已经大于0,左指针、右指针所指的值肯定大于0,那么就没有必要继续往后找了,这里优化的是

for i in range(total_len): 减少遍历次数

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        total_len = len(nums)
        total_list = []
        if total_len < 3:
            return total_list
        sorted_nums = sorted(nums)
        i = 0
        while i < total_len and sorted_nums[i] <= 0:
            if i > 0 and sorted_nums[i] == sorted_nums[i-1]:
                i += 1
                continue
            l_num = i + 1
            r_num = total_len - 1
            while l_num < r_num:
                sums = sorted_nums[l_num] + sorted_nums[r_num] + sorted_nums[i]
                if sums == 0:
                    total_list.append([sorted_nums[l_num], sorted_nums[r_num], sorted_nums[i]])
                    l_num = self.move_left_num(l_num, r_num, sorted_nums)        
                    r_num = self.move_right_num(l_num, r_num, sorted_nums)
                elif sums > 0:
                    r_num = self.move_right_num(l_num, r_num, sorted_nums)             
                else:
                    l_num = self.move_left_num(l_num, r_num, sorted_nums)   
            i += 1
                 
        return total_list

    def move_left_num(self, l_num, r_num, sorted_nums):
        while l_num + 1 < r_num and sorted_nums[l_num] == sorted_nums[l_num + 1]: 
            l_num += 1
        l_num += 1
        return l_num

    def move_right_num(self, l_num, r_num, sorted_nums):
        while l_num + 1 < r_num and sorted_nums[r_num] == sorted_nums[r_num - 1]: 
            r_num -= 1 
        r_num -= 1
        return r_num

好的,996,我谢谢你 :)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值