title: LeetCode 第 15 号问题:三数之和(中等)
date: '2020-5-23'
updated: '2020-5-25'
tags: [LeetCode]
题目:
# 给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复
# 的三元组。
#
# 注意:答案中不可以包含重复的三元组。
#
#
#
# 示例:
#
# 给定数组 nums = [-1, 0, 1, 2, -1, -4],
#
# 满足要求的三元组集合为:
# [
# [-1, 0, 1],
# [-1, -1, 2]
# ]
题目解析
题目需要我们找出三个数且和为 0 ,那么除了三个数全是 0 的情况之外,肯定会有负数和正数,所以一开始可以先选择一个数,然后再去找另外两个数,这样只要找到两个数且和为第一个选择的数的相反数就行了。也就是说需要枚举 a 和 b ,将 c 的存入 map 即可。
需要注意的是返回的结果中,不能有有重复的结果。这样的代码时间复杂度是 O(n^2)。在这里可以先将原数组进行排序,然后再遍历排序后的数组,这样就可以使用双指针以线性时间复杂度来遍历所有满足题意的两个数组合。
动画描述
待更新
代码实现
方法一:暴力破解法:三层for循环
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
res = []
nums.sort() # 对列表进行排序,方便后面的循环操作
for i in range(len(nums) - 2): # 找出第一个数
for j in range(i+1, len(nums) - 1): # 第二个数
for k in range(j + 1, len(nums)): # 第三个数
if nums[k] + nums[i] + nums[j] == 0 and [nums[i], nums[j], nums[k]] not in res:
# 使用not in res 会加大时间复杂度
res.append([nums[i],nums[j], nums[k]])
return re
运行结果:
由于时间复杂度为O(n^4),所以运行超时。
方法二:指针+排序
解法分析:
1.双指针法铺垫:先将给定nums
排序,复杂度为O(NlogN)O(NlogN)。
2.双指针法思路: 固定3 个指针中最左(最小)数字的指针 k,双指针 i,j 分设在数组索引 (k, len(nums))(k,len(nums)) 两端,通过双指针交替向中间移动,记录对于每个固定指针 k 的所有满足 -- nums[k] = nums[i] + nums[j] 的 i,j 组合:
- 分三种情况进行讨论:
- 1.num[k] > 0 时退出程序
- 2.--num[k] < nums[i] + nums[j] 此时i往左移,即 i += 1
- 3.--num[k] > nums[i] + nums[j] 此时i往左移,即 j -= 1
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort()#对数组进行排序
res,k=[],0 #res用来返回新的列表
for k in range(len(nums)-2):
#由于第一个数只有是负数才能够正常进行
if nums[k] > 0:
break
# 引入三个指针,将对k指针尽心讨论
if k > 0 and num[k] == nums[k - 1]: # 对k值是否相等进行讨论
continue
i, j = k+1, len(nums) - 1 # i,j 两个指针从下标为1和下标为last开始移动
while i<j:
s = nums[k] + nums[i] + nums[j]
if s < 0: #当s<0的话,说明此时的值还是太小,需要往大的数进行移动
i +=1 # 在运行完成之后还要考虑i是不是在
elif s > 0:
j -= 1 # 同上
else:
res.append((nums[k],nums[i],nums[j]))
#对新的列表进行更新
# 解决上面的问题:出现多个i 和 j 怎么处理, 当
while i<j and nums[i] == nums[i+1]:
i+=1
while i<j and nums[j] == nums[j-1]:
j-=1
i += 1;j -= 1
return res
运行结果
复杂度分析:
- 时间复杂度 O(N^2):其中固定指针
k
循环复杂度 O(N),双指针i,j
复杂度 O(N) - 空间复杂度 O(1):指针使用常数大小的额外空间。
方法三:哈希表解法
待更新
title: LeetCode 第 283 号问题:零移动(简单)
date: '2020-5-24'
updated: '2020-5-25'
tags: [LeetCode]
题目:
# 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
#
# 示例:
#
# 输入: [0,1,0,3,12]
# 输出: [1,3,12,0,0]
#
# 说明:
#
#
# 必须在原数组上操作,不能拷贝额外的数组。
# 尽量减少操作次数。
#
# Related Topics 数组 双指针
题目分析:
设定一个临时变量 k = 0,遍历数组 nums ,将非零元素移动到 nums[k]位 置,同时 k++,而后将[k,….nums.size()]中的元素置零。
方法一:暴力破解法
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
"""
遍历 nums ,将 nums 中为0的使用append方法添加到列表后,再紧接着把0移出列表
Do not return anything, modify nums in-place instead.
"""
# 暴力破解法
for i in nums[:]:
if i == 0:
nums.append(0)
nums.remove(0)
时间复杂度分析:
由于使用for循环,所以时间复杂度为O(n)
方法二:指针法
解析方法:
1.首先定义两个指针分别为 i,j
2.使用在指针中常用的夹击法,一个i指针从下标为0的位置出发,j指针从下标为last进行移动
3.j指针是用来将数字0移动到last,并且i 和 j 的元素交换位置1就可以实现,在python中交换两个数的值是比较简单的。
动画描述:
#方法二:进行值的交换
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
i = 0
j = len(nums)
for i in range(len(nums)):
if nums[i] != 0:
nums[i],nums[j] = nums[j],nums[i]
j -= 1
时间复杂度分析:时间复杂度为O(n),空间复杂度O(1)
总结:解决此类问题:一般采用双指针法和用栈进行维护