标签:index right 15 nums 三数 List result leetcode left
吃饭前需要等室友,写一下这道题的解题历程。
文章目录
三数之和
先贴个图
暴力解法
这里的暴力体现在两个方面:一是暴力循环查找三个数,二是暴力判断当前解是否已经在解集中。
直接遍历
一开始想到只需要遍历所有正数或者负数,然后找到合适的解即可(这里三个0会是特殊情况,因此单独处理)。但是这里我将正数和负数直接分成了两个数组,这样会造成下面情况的忽略:
假设我只遍历正数,并只从负数中找到三数和为0的情况,则必然忽略(正,正,负)的情况
于是我马上想到,那我正负都遍历一遍不就可以了吗?于是写出了如下的代码:
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
if len(nums)<3:
return []
nums = sorted(nums)
result = []
if 0 in nums:
i = nums.index(0)
if i+2<len(nums) and nums[i+2]==0:
result.append([0, 0, 0])
nums1 = [x for x in nums if x>0]
nums2 = [x for x in nums if x<=0]
for a in nums1:
for i in range(len(nums2)-1):
for j in range(i+1, len(nums2)):
if a+nums2[i]+nums2[j]==0:
tmp = sorted([a, nums2[i], nums2[j]])
if tmp not in result:
result.append(tmp)
for a in nums2:
for i in range(len(nums1)-1):
for j in range(i+1, len(nums1)):
if a+nums1[i]+nums1[j]==0:
tmp = sorted([a, nums1[i], nums1[j]])
if tmp not in result:
result.append(tmp)
return result
emmm说实话,这不仅是多重循环,还是反复的多重循环,果不其然出现了超时
查找优化
在直接进行暴力遍历后,我想到一部分遍历可以改为查找,而集合、字典等数据结构的查找是很快的,于是我将上面的代码改成了
- 首先去除重复情况
- 在不重复的集合中查找满足条件的情况
考虑到去重令人头疼,因此直接将重复的情况排除,然后使用集合来查找满去条件的元素。
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
if len(nums)<3:
print('[]')
result = []
for num in nums:
if num != 0 and nums.count(num)>1 and -2*num in nums:
tmp = sorted([num, num, -2*num])
if tmp not in result:
result.append(tmp)
if nums.count(0)>=3:
result.append([0, 0, 0])
from sortedcontainers import SortedSet
nums = SortedSet(nums)
for i in range(len(nums)):
if nums[i] < 0:
for j in range(i+1, len(nums)):
if -(nums[i]+nums[j]) in nums and nums.index(-(nums[i]+nums[j]))>j:
result.append([nums[i], nums[j], -nums[i]-nums[j]])
return result
总算是通过了,但是效果很不好8000ms+
双指针求解
双指针1
看了题解,发现双指针解法应是较快的方法。
双指针求解首先将数组进行排序,然后利用有序数组的特点进行遍历,这样能少一重循环且内层循环是双指针:
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
if len(nums)<3:
print('[]')
result = []
# 双指针求解
nums = sorted(nums)
length = len(nums)
for i in range(length):
if nums[i]>0: break
left_index = i+1
right_index = length-1
while right_index > left_index:
tmp = nums[i] + nums[left_index] + nums[right_index]
if tmp > 0:
right_index -= 1
elif tmp < 0:
left_index += 1
else:
suspicious = [nums[i], nums[left_index], nums[right_index]]
if suspicious not in result:
result.append(suspicious)
right_index -= 1
left_index += 1
return rusult
简单使用了双指针解法后,时间缩短到2900ms左右,但时间仍然很长,只超过了10%的用户。
双指针2
在考虑了双指针1较为耗费时间的地方,我发现在进行结果去重的时候每一次都要进行查找,这几乎相当于一个双重循环下的遍历查找,必然极大降低了效率。经过思考后,我发现只需要当前的解和上一次的解不重复即可,比如[-1, -1, 0, 0, 1, 1]这个数组,首先从最左侧-1开始,找到0(index=2)和1(index=5),然后再次找到0(index=3)和1(index=4),这样重复的情况必然是连续发生。
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
length = len(nums)
if length < 3:
print('[]')
result = [1]
# 双指针求解
nums.sort()
for i in range(length):
if nums[i]>0: break
if i>=1 and nums[i]==nums[i-1]: continue
left_index = i+1
right_index = length-1
while right_index > left_index:
tmp = nums[i] + nums[left_index] + nums[right_index]
if tmp > 0:
right_index -= 1
elif tmp < 0:
left_index += 1
else:
suspicious = [nums[i], nums[left_index], nums[right_index]]
if suspicious != result[-1]:
result.append(suspicious)
right_index -= 1
left_index += 1
return result[1:]
这样时间缩短至370+ms,速度尚可,至于内存消耗虽然只超过了19.78%的用户,但短时间也没想到什么好方法。
标签:index,right,15,nums,三数,List,result,leetcode,left 来源: https://blog.csdn.net/qq_34769162/article/details/114740567
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。