首先了解下数据结构的特点
栈:先进后出
队列:先进先出
一、用栈实现队列
LeetCode232 力扣
思路分析
一个栈当做输入栈,用于压入push传入的数据;一个栈当做输出栈,用于pop和peek操作;当输出栈为空时,将输入栈的数据依次弹出并压入输出栈中。
代码实现
class MyQueue:
# 栈:先进后出
# 队列:先进先出
def __init__(self):
self.stack_in = []
self.stack_out = []
def push(self, x: int) -> None:
self.stack_in.append(x)
def pop(self) -> int:
if self.empty():
return None
if self.stack_out:
return self.stack_out.pop()
else:
while self.stack_in:
self.stack_out.append(self.stack_in.pop())
return self.stack_out.pop()
def peek(self) -> int:
ans = self.pop()
if ans:
self.stack_out.append(ans)
return ans
def empty(self) -> bool:
return not (self.stack_in or self.stack_out)
二、用队列实现栈
LeetCode225 力扣
思路分析
栈的特征:后进先出
队列的特征:先进先出
两个队列queue1和queue2,queue1用于存储栈内的元素,queue2作为入栈操作的辅助队列;需要满足queue1前端元素为最后入栈的元素,入栈操作时,将元素入到队列queue2,然后queue1元素依次出队后再入队到queue2
代码实现
class MyStack:
# python中队列实现 collectioons.deque() 入队列append,出队列popleft()
def __init__(self):
self.queue1 = collections.deque()
self.queue2 = collections.deque()
def push(self, x: int) -> None:
self.queue2.append(x)
while self.queue1:
self.queue2.append(self.queue1.popleft())
self.queue1, self.queue2 = self.queue2, self.queue1
def pop(self) -> int:
return self.queue1.popleft()
def top(self) -> int:
return self.queue1[0]
def empty(self) -> bool:
return not self.queue1
三、n数之和
1. 两数之和
LeetCode1 力扣
思路分析
方法1:两层循环
第一层确定一个数,然后内层循环继续遍历后续元素,判断是否存在 target - x 的数
方法2:哈希表
创建一个空哈希表,对于每一个元素x,我们首先查询哈希表中是否存在 target - x,如果不存在将x插入到哈希表中,即可保证不会让x和自己匹配
代码实现
方法1:两层循环
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
# 方法1:两层循环
n = len(nums)
for i in range(n):
for j in range(i+1, n):
if nums[i] + nums[j] == target:
return [i,j]
方法2:哈希表
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
# 方法2:哈希表
# 对于每一个x,首先查询哈希表中是否存在 target-x,然后将 x 插入到哈希表中,即可保证不会让 x 和自己匹配
hashtable = {}
for i, val in enumerate(nums):
if target-val in hashtable:
return [hashtable[target-val], i]
hashtable[val] = i
return []
2. 三数之和
LeetCode 15 力扣
思路分析
方法1:三层循环
时间复杂度高,O(n^3),弃用
注:功能上可以实现,但是时间复杂度高,超出时间限制,弃用
方法2:双层循环+hash
固定一个数target,再利用两数之和的思想去map中存取或查找 (-1)*target - nums[j],但是这样的问题是无法消除重复结果,如果我们在增加一个去重方法,将导致超时
注:功能上可以实现,但是时间复杂度高,超出时间限制,弃用
方法3:排序+双指针
先将数组排序处理重复结果,让后还是固定一个元素,由于数据是排好序的,所有我们用双指针来不断寻找即可求解
代码实现
方法1:三层循环
注:功能上可以实现,但是时间复杂度高,超出时间限制,弃用
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
# 方法1:三层循环
ans_list = []
n = len(nums)
for i in range(n):
for j in range(i + 1, n):
for k in range(j + 1, n):
if nums[i] + nums[j] + nums[k] == 0:
num_list = sorted([nums[i], nums[j], nums[k]])
if num_list not in ans_list:
ans_list.append(num_list)
return ans_list
方法2:双层循环+hash
注:功能上可以实现,但是时间复杂度高,超出时间限制,弃用
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
# 方法2:两层循环+hash
ans_list = []
n = len(nums)
for i in range(n):
target = nums[i]
hashtable = {}
for j, val in enumerate(nums):
if -target-val in hashtable and i!=j and i!=hashtable[-target-val]:
num_list = sorted([target, -target-val, val])
if num_list not in ans_list:
ans_list.append(num_list)
hashtable[val] = j
return ans_list
方法3:排序+双指针
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
# 方法3:排序+双指针
# a+b+c=0
n = len(nums)
ans_list = []
nums.sort()
# 枚举a
for first in range(n):
# 确保和上一次枚举的数不同
if first > 0 and nums[first] == nums[first-1]:
continue
# c对应的指针指向数组的最右端
third=n-1
target = -nums[first]
# 枚举b
for second in range(first+1, n):
# 确保和上一次枚举的数不同
if second > first+1 and nums[second] == nums[second-1]:
continue
# 保证b的指针的c的指针的左侧
while second < third and nums[second] + nums[third] > target:
third -= 1
# 如何指针重合,可以提前退出循环,随着b增加,不会有满足a+b+c=0 且 c>b的情况
if second == third:
break
if nums[second] + nums[third] == target:
ans_list.append([nums[first], nums[second], nums[third]])
return ans_list