暴力解题:
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,我谢谢你 :)