设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。
push(x) – 将元素 x 推入栈中。
pop() – 删除栈顶的元素。
top() – 获取栈顶元素。
getMin() – 检索栈中的最小元素。
示例:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.
解法:
解法一:
class MinStack(object):
def __init__(self):
"""
initialize your data structure here.
"""
self.stack = []
self.min = None
def push(self, x):
"""
:type x: int
:rtype: None
"""
self.stack.append(x)
if self.min == None or self.min > x:
self.min = x
def pop(self):
"""
:rtype: None
"""
tmp = self.stack.pop()
if len(self.stack) == 0:
self.min = None
if self.min == tmp:
self.min = self.stack[0]
for x in self.stack:
if self.min > x:
self.min = x
def top(self):
"""
:rtype: int
"""
return self.stack[-1]
def getMin(self):
"""
:rtype: int
"""
return self.min
# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(x)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.getMin()
解法二:
class MinStack:
def __init__(self):
self.stack = []
self.minstack = []
def push(self, x: int) -> None:
self.stack.append(x)
if not self.minstack or x <= self.minstack[-1]:
self.minstack.append(x)
def pop(self) -> None:
x = self.stack.pop()
if x == self.minstack[-1]:
self.minstack.pop()
def top(self) -> int:
return self.stack[-1]
def getMin(self) -> int:
return self.minstack[-1]
栈排序。 编写程序,对栈进行排序使最小元素位于栈顶。最多只能使用一个其他的临时栈存放数据,但不得将元素复制到别的数据结构(如数组)中。该栈支持如下操作:push、pop、peek 和 isEmpty。当栈为空时,peek 返回 -1。
示例1:
输入:
[“SortedStack”, “push”, “push”, “peek”, “pop”, “peek”]
[[], [1], [2], [], [], []]
输出:
[null,null,null,1,null,2]
示例2:
输入:
[“SortedStack”, “pop”, “pop”, “push”, “pop”, “isEmpty”]
[[], [], [], [1], [], []]
输出:
[null,null,null,null,null,true]
说明:
栈中的元素数目在[0, 5000]范围内。
解法
用一个辅助栈
class SortedStack:
def __init__(self):
self.data = []
self.helper = []
def push(self, val: int) -> None:
if not self.data: # 如果 data 为空,直接将元素添加到data中
self.data.append(val)
else:
# 如果 data 顶的元素比val小,将 data 中比 val 小的元素倒到 helper 中
#然后将 val 放入 data 顶
if self.data[-1] < val:
while self.data and self.data[-1] < val:
self.helper.append(self.data.pop(-1))
self.data.append(val)
# 如果 data 顶的元素等于 val,直接将 val 放在 data 顶
elif self.data[-1] == val:
self.data.append(val)
else:
# 此时的情况为:val < sel.data[-1],需要把 helper 中比 val 大的元素倒到data顶去
# case 1, 如果helper 为空,或者 val 大于等于 helper 顶的元素
# 直接将val 放到 data 顶
if not self.helper or self.helper[-1] <= val:
self.data.append(val)
else:
# case 2, val 小于 helper 的栈顶元素,则把小于 val 的元素倒回 data 中
# 然后把 val 放在 data 栈顶
while self.helper and val < self.helper[-1]:
self.data.append(self.helper.pop())
self.data.append(val)
def pop(self) -> None:
if not self.data:
return -1
# 由于 helper 中会放有较小的元素,
# 首先检查 helper 是否有元素,有的话将其倒入 data 中
# pop data 顶的元素(当前最小值)
while self.helper:
self.data.append(self.helper.pop())
return self.data.pop()
def peek(self) -> int:
if not self.data:
return -1
while self.helper:
self.data.append(self.helper.pop())
return self.data[-1]
def isEmpty(self) -> bool:
return self.data == []
中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。
例如,
[2,3,4] 的中位数是 3
[2,3] 的中位数是 (2 + 3) / 2 = 2.5
设计一个支持以下两种操作的数据结构:
void addNum(int num) - 从数据流中添加一个整数到数据结构中。
double findMedian() - 返回目前所有元素的中位数。
示例:
addNum(1)
addNum(2)
findMedian() -> 1.5
addNum(3)
findMedian() -> 2
进阶:
如果数据流中所有整数都在 0 到 100 范围内,你将如何优化你的算法?
如果数据流中 99% 的整数都在 0 到 100 范围内,你将如何优化你的算法?
解法
对于有序数组求中位数很简单了,但是题目给的是数据流,也就是我们必须做到可以时刻求出中位数的程度。
第一种方法:我们可以给每个从数据流出来的数进行排序,然后数组长度除以2就能得到中位数,但显然这样的做法是非常不好的,如果新进来的数是比当前排好序的所有元素都小的数,那么意味着数组中的所有数都必须向后移动一位,也就是O(n)的复杂度,假设每进来一个数都来一遍O(n),性能还是很低的。
第二种方法:采用优先队列,也就是大根堆跟小根堆,我们将较小的n/2个数放到大根堆中,将较大的n/2个数放到小根堆中,显然,如果n是偶数,那么大根堆的堆顶跟小根堆的堆顶就是我们要找的两个中位数,将其相加除以2作为结果返回即可。如果n是奇数,那么就看大根堆跟小根堆谁的节点个数比另一个堆多一个,节点数量多的那个堆的堆顶就是我们要找的中位数,此时我们直接返回结果即可。
需要注意的是:
1.对于取堆顶元素的操作的时间复杂度是常数级别的。
2.插入新节点时我们需要判断节点的值是否小于大根堆堆顶的值或者大于小根堆堆顶的值,
如果小于大根堆堆顶的值,那么节点应该插入大根堆,反过来应该插入小根堆。
3.每次插入新节点我们还需要判断两个堆之间的元素个数是否平衡。插入新节点后,我们判断两个堆的元素个数,如果相差为2那么我们就要对堆进行调整。比如新插入一个节点到小根堆中,而此时大根堆的个数+1小于小根堆的节点个数,这个时候只需要将小根堆的堆顶元素弹出,然后将这个弹出的元素插入大根堆即可。反过来也是一样的操作。为什么可以这样做呢?这是因为我们说了小根堆保存的是较大的n/2个数,而小根堆的堆顶是小根堆中最小的元素,同时也是大根堆中最大的元素,因此我们将这个堆顶元素弹出并插入大根堆的操作并不会破坏“小根堆保存较大的n/2个数,大根堆保存较小的n/2”这样的前提。
class MedianFinder:
def __init__(self):
"""
initialize your data structure here.
"""
self.max_heap = []
self.min_heap = []
def addNum(self, num):
if not self.max_heap:
heapq.heappush(self.max_heap, -num) # python的heaqp模块是小根堆,因此要保存大根堆的话需要加上一个负号
return
if num > -self.max_heap[0]:
heapq.heappush(self.min_heap, num)
if len(self.max_heap) + 1 < len(self.min_heap):
heapq.heappush(self.max_heap, -heapq.heappop(self.min_heap)) # 插入大根堆需要给值加负号
else:
heapq.heappush(self.max_heap, -num)
if len(self.max_heap) > len(self.min_heap) + 1:
heapq.heappush(self.min_heap, -heapq.heappop(self.max_heap)) # 弹出大根堆堆顶的时候需要加负号变为正数
def findMedian(self):
if len(self.max_heap) > len(self.min_heap): # 大根堆元素多一个,中位数是大根堆堆顶
return -self.max_heap[0]
if len(self.max_heap) < len(self.min_heap): # 小根堆元素多一个,中位数是小根堆堆顶
return self.min_heap[0]
else:
return (-self.max_heap[0] + self.min_heap[0])/2
# Your MedianFinder object will be instantiated and called as such:
# obj = MedianFinder()
# obj.addNum(num)
# param_2 = obj.findMedian()
在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
示例 1:
输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
示例 2:
输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4
说明:
你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。
解法
class Solution(object):
def findKthLargest(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
return self.quick(nums, 0, len(nums)-1, k-1)
def quick(self, nums, l, r, k):
if l == r:
return nums[l]
p = self.partition(nums, l, r)
if p == k:
return nums[p]
elif k < p:
return self.quick(nums, l, p-1, k)
else:
return self.quick(nums, p+1, r, k)
def partition(self, nums, l, r):
j = l
for i in range(l+1, r+1):
if nums[i] > nums[l]:
j+=1
nums[i], nums[j] = nums[j], nums[i]
nums[j], nums[l] = nums[l], nums[j]
return j
解法3:
class Solution:
def _partition(self, nums, l, r):
j = l
for i in range(l + 1, r + 1):
if nums[i] > nums[l]:
j += 1
nums[i], nums[j] = nums[j], nums[i]
nums[l], nums[j] = nums[j], nums[l]
return j
def findKthLargest(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
l, r, k = 0, len(nums) - 1, k - 1
while 1:
p = self._partition(nums, l, r)
if k == p:
return nums[p]
elif k < p:
r = p - 1
else:
l = p + 1
给定一个 n x n 矩阵,其中每行和每列元素均按升序排序,找到矩阵中第k小的元素。
请注意,它是排序后的第k小元素,而不是第k个元素。
示例:
matrix = [
[ 1, 5, 9],
[10, 11, 13],
[12, 13, 15]
],
k = 8,
返回 13。
说明:
你可以假设 k 的值永远是有效的, 1 ≤ k ≤ n2 。
解法:
class Solution(object):
def kthSmallest(self, matrix, k):
"""
:type matrix: List[List[int]]
:type k: int
:rtype: int
"""
a, b = len(matrix), len(matrix[0])
left = matrix[0][0]
right = matrix[a-1][b-1]
while left < right:
mid = left + (right - left) / 2
cnt = 0
for i in range(a):
j = b-1
while j >=0 and matrix[i][j] > mid:
j -= 1
cnt += j+1
if cnt < k:
left = mid + 1
else:
right = mid
return left
给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
示例:
输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
输出: [3,3,5,5,6,7]
解释:
滑动窗口的位置 最大值
--------------- -----
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
解法
Sliding Window法。
维护window这个数组,使得在任意时刻,window【0】都是当前Window内最大值的下标。
并且window从左到右恰恰是第一大、第二大、。。。。。第K大的元素(也就是C++中的双端队列,在队列中存储元素在数组中的位置, 并且维持队列的严格递减)
维护过程为:
class Solution(object):
def maxSlidingWindow(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: List[int]
"""
if not nums:
return []
res, window = [], []
for index, item in enumerate(nums):
if window and window[0] <= index - k:
window.pop(0)
while window and nums[window[-1]] <= item:
window.pop()
window.append(index)
if index >= k-1:
res.append(nums[window[0]])
return res
实现一个基本的计算器来计算一个简单的字符串表达式的值。
字符串表达式仅包含非负整数,+, - ,*,/ 四种运算符和空格 。 整数除法仅保留整数部分。
示例 1:
输入: “3+2*2”
输出: 7
示例 2:
输入: " 3/2 "
输出: 1
示例 3:
输入: " 3+5 / 2 "
输出: 5
说明:
你可以假设所给定的表达式都是有效的。
请不要使用内置的库函数 eval。
解法
计算器的实现一般是使用压栈的方式,但此处有几个注意事项:
class Solution(object):
def calculate(self, s):
"""
:type s: str
:rtype: int
"""
s = s.replace(' ', '')
res = []
num = 0
sign = '+'
for idx, x in enumerate(s):
if x.isdigit():
num = num * 10 + int(x)
if x.isdigit() == False or idx == len(s) - 1:
if sign == '+':
res.append(num)
elif sign == '-':
res.append(-num)
elif sign == '*':
res.append(res.pop() * num)
elif sign == '/':
res.append(int(float(res.pop())/float(num)))
num = 0
sign = x
out = 0
for idx, x in enumerate(res):
out += x
return out
根据逆波兰表示法,求表达式的值。
有效的运算符包括 +, -, *, / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
说明:
整数除法只保留整数部分。
给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
示例 1:
输入: [“2”, “1”, “+”, “3”, “*”]
输出: 9
解释: ((2 + 1) * 3) = 9
示例 2:
输入: [“4”, “13”, “5”, “/”, “+”]
输出: 6
解释: (4 + (13 / 5)) = 6
示例 3:
输入: [“10”, “6”, “9”, “3”, “+”, “-11”, “", “/”, "”, “17”, “+”, “5”, “+”]
输出: 22
解释:
((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22
解法
和计算器的方法相同,都是压栈,这个更简单,因为是后缀表达式的形式,而且不需要判断当前数字是否已经结束,因为用列表给出了。
但是要注意不能用.isdigit去判断是否是数字,因为这只能判断0-9的数字,当遇到”-11“这种就错了。
class Solution(object):
def evalRPN(self, tokens):
"""
:type tokens: List[str]
:rtype: int
"""
res = []
for idx, x in enumerate(tokens):
if x != '+' and x != '-' and x != "*" and x != "/":
res.append(int(x))
else:
b=res.pop()
a=res.pop()
tmp = 0
if x == '+':
tmp=a+b
elif x == '-':
tmp = a - b
elif x == '*':
tmp = a * b
elif x == '/':
tmp = int(float(a) / float(b))
res.append(tmp)
return res[-1]
你有一个带有四个圆形拨轮的转盘锁。每个拨轮都有10个数字: ‘0’, ‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’ 。每个拨轮可以自由旋转:例如把 ‘9’ 变为 ‘0’,‘0’ 变为 ‘9’ 。每次旋转都只能旋转一个拨轮的一位数字。
锁的初始数字为 ‘0000’ ,一个代表四个拨轮的数字的字符串。
列表 deadends 包含了一组死亡数字,一旦拨轮的数字和列表里的任何一个元素相同,这个锁将会被永久锁定,无法再被旋转。
字符串 target 代表可以解锁的数字,你需要给出最小的旋转次数,如果无论如何不能解锁,返回 -1。
示例 1:
输入:deadends = [“0201”,“0101”,“0102”,“1212”,“2002”], target = “0202”
输出:6
解释:
可能的移动序列为 “0000” -> “1000” -> “1100” -> “1200” -> “1201” -> “1202” -> “0202”。
注意 “0000” -> “0001” -> “0002” -> “0102” -> “0202” 这样的序列是不能解锁的,
因为当拨动到 “0102” 时这个锁就会被锁定。
示例 2:
输入: deadends = [“8888”], target = “0009”
输出:1
解释:
把最后一位反向旋转一次即可 “0000” -> “0009”。
示例 3:
输入: deadends = [“8887”,“8889”,“8878”,“8898”,“8788”,“8988”,“7888”,“9888”], target = “8888”
输出:-1
解释:
无法旋转到目标数字且不被锁定。
示例 4:
输入: deadends = [“0000”], target = “8888”
输出:-1
提示:
死亡列表 deadends 的长度范围为 [1, 500]。
目标数字 target 不会在 deadends 之中。
每个 deadends 和 target 中的字符串的数字会在 10,000 个可能的情况 ‘0000’ 到 ‘9999’ 中产生。
解法
首先是求“最小”次数,所以用BFS。本来用了vis另一个set保存遍历过的元素,但是发现其实可以和deadends合并,省时间和空间。
注意每次加入“树的子节点”的时候,都是加入8个(4位数,8种改变的可能)
class Solution(object):
def openLock(self, deadends, target):
"""
:type deadends: List[str]
:type target: str
:rtype: int
"""
ori = "0000"
if ori in deadends:
return -1
q = [(ori, 0)]
deadends = set(deadends)
while q:
top, step = q.pop(0)
if top == target:
return step
for i in range(4):
x = [(int(top[i]) + 1) % 10, (int(top[i]) - 1) % 10]
for j in range(2):
k = str(x[j])
cur = top[:i] + k + top[i+1:]
if cur not in deadends:
deadends.add(cur)
q.append((cur, step+1))
return -1
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
示例 1:
输入: “()”
输出: true
示例 2:
输入: “()[]{}”
输出: true
示例 3:
输入: “(]”
输出: false
示例 4:
输入: “([)]”
输出: false
示例 5:
输入: “{[]}”
输出: true
解法
首先读懂题目,判断括号是否有效;然后找到有效的条件:
class Solution(object):
def isValid(self, s):
"""
:type s: str
:rtype: bool
"""
if not s:
return True
stack = []
for x in s:
#print(x)
if x == "(" or x == "{" or x == "[":
stack.append(x)
if x == ')':
if not stack or stack.pop() != '(':
return False
if x == '}':
if not stack or stack.pop() != '{':
return False
if x == ']':
if not stack or stack.pop() != '[':
return False
if not stack:
return True
return False
根据每日 气温 列表,请重新生成一个列表,对应位置的输入是你需要再等待多久温度才会升高超过该日的天数。如果之后都不会升高,请在该位置用 0 来代替。
例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。
解法
题意:遍历列表,得到最近的比当前值大的索引差值。分析可能的情况:
那么就可以想到用栈保存前面的数的位置,遍历当前数x的时候,就pop出最近的数比较一下是否比x小,如果是的话,取出来给res赋值(索引差);如果不是的话,stack前面不可能有比x更小的
class Solution(object):
def dailyTemperatures(self, T):
"""
:type T: List[int]
:rtype: List[int]
"""
res = [0] * len(T)
stack = [0]
for i in range(1, len(T)):
while len(stack) > 0 and T[stack[-1]] < T[i]:
idx = stack.pop()
res[idx] = i - idx
stack.append(i)
return res
给你无向 连通 图中一个节点的引用,请你返回该图的 深拷贝(克隆)。
图中的每个节点都包含它的值 val(int) 和其邻居的列表(list[Node])。
class Node {
public int val;
public List neighbors;
}
测试用例格式:
简单起见,每个节点的值都和它的索引相同。例如,第一个节点值为 1,第二个节点值为 2,以此类推。该图在测试用例中使用邻接列表表示。
邻接列表是用于表示有限图的无序列表的集合。每个列表都描述了图中节点的邻居集。
给定节点将始终是图中的第一个节点(值为 1)。你必须将 给定节点的拷贝 作为对克隆图的引用返回。
示例 1:
输入:adjList = [[2,4],[1,3],[2,4],[1,3]]
输出:[[2,4],[1,3],[2,4],[1,3]]
解释:
图中有 4 个节点。
节点 1 的值是 1,它有两个邻居:节点 2 和 4 。
节点 2 的值是 2,它有两个邻居:节点 1 和 3 。
节点 3 的值是 3,它有两个邻居:节点 2 和 4 。
节点 4 的值是 4,它有两个邻居:节点 1 和 3 。
示例 2:
输入:adjList = [[]]
输出:[[]]
解释:输入包含一个空列表。该图仅仅只有一个值为 1 的节点,它没有任何邻居。
示例 3:
输入:adjList = []
输出:[]
解释:这个图是空的,它不含任何节点。
示例 4:
输入:adjList = [[2],[1]]
输出:[[2],[1]]
提示:
节点数介于 1 到 100 之间。
每个节点值都是唯一的。
无向图是一个简单图,这意味着图中没有重复的边,也没有自环。
由于图是无向的,如果节点 p 是节点 q 的邻居,那么节点 q 也必须是节点 p 的邻居。
图是连通图,你可以从给定节点访问到所有节点。
解法
题意:使用图的起始节点重新构建一个相同的图。情况分析:
"""
# Definition for a Node.
class Node(object):
def __init__(self, val = 0, neighbors = []):
self.val = val
self.neighbors = neighbors
"""
class Solution(object):
def cloneGraph(self, node):
"""
:type node: Node
:rtype: Node
"""
if not node:
return None
if not node.neighbors:
return Node(val=node.val)
root = Node(val=node.val)
dic = {1: root}
q = [node]
vis = set()
while q:
ori = q.pop(0)
cur = dic[ori.val]
#print(ori.val, cur.val)
for x in ori.neighbors:
#print(x.val, dic.keys(), vis)
if x.val not in dic:
tmp = Node(x.val)
dic[x.val] = tmp
cur.neighbors.append(dic[x.val])
if x.val not in vis and x not in q:
q.append(x)
vis.add(ori.val)
return root
给定一个非负整数数组,a1, a2, …, an, 和一个目标数,S。现在你有两个符号 + 和 -。对于数组中的任意一个整数,你都可以从 + 或 -中选择一个符号添加在前面。
返回可以使最终数组和为目标数 S 的所有添加符号的方法数。
示例 1:
输入: nums: [1, 1, 1, 1, 1], S: 3
输出: 5
解释:
-1+1+1+1+1 = 3
+1-1+1+1+1 = 3
+1+1-1+1+1 = 3
+1+1+1-1+1 = 3
+1+1+1+1-1 = 3
一共有5种方法让最终目标和为3。
注意:
数组非空,且长度不会超过20。
初始的数组的和不会超过1000。
保证返回的最终结果能被32位整数存下。
解法
题意:返回加减数组中每个数字和为目标数 S 的所有可能性。(如果用动态规划的思路的话:在背包问题中,我们要考虑物品放还是不放)
很快想到用DFS,定义函数f(i,target)表示i长度内目标为target的方法数,那么f(i,target)=f(i−1,target−nums[i])+f(i−1,target+nums[i])。直接这样做容易超时,所以可以想到用一个字典保存下来已经遍历过的方法数目。
class Solution(object):
def findTargetSumWays(self, nums, S):
"""
:type nums: List[int]
:type S: int
:rtype: int
"""
vis = {(0, 0): 1}
res = self.dfs(nums, S, vis)
return res
def dfs(self, nums, S, vis):
if (len(nums), S) in vis:
return vis[(len(nums), S)]
elif len(nums) == 0:
return 0
vis[(len(nums), S)] = self.dfs(nums[1:], S - nums[0], vis) + self.dfs(nums[1:], S + nums[0], vis)
return vis[(len(nums), S)]
给定一个二叉树,返回它的中序 遍历。
示例:
输入: [1,null,2,3]
1
\
2
/
3
输出: [1,3,2]
输出: [1,3,2]
进阶: 递归算法很简单,你可以通过迭代算法完成吗?
解法
使用迭代方法
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def inorderTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[int]
"""
if root == None:
return []
res = []
cur = root
stack = []
while stack or cur:
if cur:
stack.append(cur)
cur = cur.left
else:
cur = stack.pop()
res.append(cur.val)
cur = cur.right
return res
给定一个经过编码的字符串,返回它解码后的字符串。
编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。
你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。
此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。
示例:
s = “3[a]2[bc]”, 返回 “aaabcbc”.
s = “3[a2[c]]”, 返回 “accaccacc”.
s = “2[abc]3[cd]ef”, 返回 “abcabccdcdcdef”.
解法
题意:类似于计算器,返回k*字符串内部子串的结果
思路:遇到不同类型的字符进行不同方式处理,几种情况:
自己写的,比较麻烦:
class Solution(object):
def decodeString(self, s):
"""
:type s: str
:rtype: str
"""
if not s:
return ""
stack = []
for i, x in enumerate(s):
if x != "]":
stack.append(x)
else:
tmp = []
while stack[-1] != "[":
tmp.append(stack.pop())
tmp = tmp[::-1]
stack.pop()
k = ""
while len(stack) > 0 and stack[-1].isdigit():
k = stack.pop() + k
k = int(k)
while k > 0:
stack.extend(tmp)
k -= 1
return "".join(stack)
网上看的比较清晰简洁的方法:
class Solution(object):
def decodeString(self, s):
"""
:type s: str
:rtype: str
"""
stack = []
curNum = 0
curString = ''
for c in s:
if c == '[':
stack.append(curString)
stack.append(curNum)
curString = ''
curNum = 0
elif c == ']':
num = stack.pop()
prevString = stack.pop()
curString = prevString + num * curString
elif c.isdigit():
curNum = curNum * 10 + int(c)
else:
curString += c
return curString
有一幅以二维整数数组表示的图画,每一个整数表示该图画的像素值大小,数值在 0 到 65535 之间。
给你一个坐标 (sr, sc) 表示图像渲染开始的像素值(行 ,列)和一个新的颜色值 newColor,让你重新上色这幅图像。
为了完成上色工作,从初始坐标开始,记录初始坐标的上下左右四个方向上像素值与初始坐标相同的相连像素点,接着再记录这四个方向上符合条件的像素点与他们对应四个方向上像素值与初始坐标相同的相连像素点,……,重复该过程。将所有有记录的像素点的颜色值改为新的颜色值。
最后返回经过上色渲染后的图像。
示例 1:
输入:
image = [[1,1,1],[1,1,0],[1,0,1]]
sr = 1, sc = 1, newColor = 2
输出: [[2,2,2],[2,2,0],[2,0,1]]
解析:
在图像的正中间,(坐标(sr,sc)=(1,1)),
在路径上所有符合条件的像素点的颜色都被更改成2。
注意,右下角的像素没有更改为2,
因为它不是在上下左右四个方向上与初始点相连的像素点。
注意:
image 和 image[0] 的长度在范围 [1, 50] 内。
给出的初始点将满足 0 <= sr < image.length 和 0 <= sc
解法
很显然就是”迷宫“类问题,用dfs即可。也可以用队列解决
dfs方法:
class Solution(object):
def floodFill(self, image, sr, sc, newColor):
"""
:type image: List[List[int]]
:type sr: int
:type sc: int
:type newColor: int
:rtype: List[List[int]]
"""
if not image:
return image
curC = image[sr][sc]
self.vis = [[False for i in range(len(image[0]))] for j in range(len(image))]
image = self.dfs(image, sr, sc, curC, newColor)
return image
def dfs(self, image, r, c, curC, newC):
image[r][c] = newC
self.vis[r][c] = True
if r > 0 and image[r - 1][c] == curC and not self.vis[r - 1][c]:
image = self.dfs(image, r - 1, c, curC, newC)
if r < len(image) - 1 and image[r + 1][c] == curC and not self.vis[r + 1][c]:
image = self.dfs(image, r + 1, c, curC, newC)
if c > 0 and image[r][c - 1] == curC and not self.vis[r][c - 1]:
image = self.dfs(image, r, c - 1, curC, newC)
if c < len(image[0]) - 1 and image[r][c + 1] == curC and not self.vis[r][c + 1]:
image = self.dfs(image, r, c + 1, curC, newC)
return image
队列:
class Solution(object):
def floodFill(self, image, sr, sc, newColor):
"""
:type image: List[List[int]]
:type sr: int
:type sc: int
:type newColor: int
:rtype: List[List[int]]
"""
m, n = len(image), len(image[0])
color = image[sr][sc]
image[sr][sc] = newColor
visited = [[0 for _ in range(n + 1)] for _ in range(m + 1)]
dx = [1, -1, 0, 0]
dy = [0, 0, 1, -1]
q = deque()
q.append([sr,sc])
while q:
x0, y0 = q.popleft()
for k in range(4):
x = x0 + dx[k]
y = y0 + dy[k]
if 0 <= x < m and 0 <= y < n and image[x][y] == color and visited[x][y] == 0:
image[x][y] = newColor
visited[x][y] = 1
q.append([x, y])
return image
给定一个由 0 和 1 组成的矩阵,找出每个元素到最近的 0 的距离。
两个相邻元素间的距离为 1 。
示例 1:
输入:
0 0 0
0 1 0
0 0 0
输出:
0 0 0
0 1 0
0 0 0
示例 2:
输入:
0 0 0
0 1 0
1 1 1
输出:
0 0 0
0 1 0
1 2 1
注意:
给定矩阵的元素个数不超过 10000。
给定矩阵中至少有一个元素是 0。
矩阵中的元素只在四个方向上相邻: 上、下、左、右。
解法
题意:找离每个1最近的0的距离
步骤:因为是最近距离,显然是BFS。开始想的方法是遍历矩阵,找到每个1之后再用BFS,显然复杂度非常高。后来看到网上的做法,其实这就相当于求每个0最近的1的距离,遍历一遍矩阵就可以了。
class Solution(object):
def updateMatrix(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: List[List[int]]
"""
if not matrix:
return matrix
res = [[0 for i in range(len(matrix[0]))] for j in range(len(matrix))]
vis = [[False for ii in range(len(matrix[0]))] for jj in range(len(matrix))]
queue = []
for i in range(len(matrix)):
for j in range(len(matrix[0])):
if matrix[i][j] == 0:
queue.append((i, j, 0))
vis[i][j] = True
dx = [1, -1, 0, 0]
dy = [0, 0, 1, -1]
while queue:
x0, y0, step = queue.pop(0)
if matrix[x0][y0] == 1:
res[x0][y0] = step
step += 1
for k in range(4):
x = x0 + dx[k]
y = y0 + dy[k]
if x >= 0 and x <= len(matrix) - 1 and y >= 0 and y <= len(matrix[0]) - 1 and vis[x][y] == False:
queue.append((x, y, step))
vis[x][y] = True
return res
有 N 个房间,开始时你位于 0 号房间。每个房间有不同的号码:0,1,2,…,N-1,并且房间里可能有一些钥匙能使你进入下一个房间。
在形式上,对于每个房间 i 都有一个钥匙列表 rooms[i],每个钥匙 rooms[i][j] 由 [0,1,…,N-1] 中的一个整数表示,其中 N = rooms.length。 钥匙 rooms[i][j] = v 可以打开编号为 v 的房间。
最初,除 0 号房间外的其余所有房间都被锁住。
你可以自由地在房间之间来回走动。
如果能进入每个房间返回 true,否则返回 false。
示例 1:
输入: [[1],[2],[3],[]]
输出: true
解释:
我们从 0 号房间开始,拿到钥匙 1。
之后我们去 1 号房间,拿到钥匙 2。
然后我们去 2 号房间,拿到钥匙 3。
最后我们去了 3 号房间。
由于我们能够进入每个房间,我们返回 true。
示例 2:
输入:[[1,3],[3,0,1],[2],[0]]
输出:false
解释:我们不能进入 2 号房间。
提示:
1 <= rooms.length <= 1000
0 <= rooms[i].length <= 1000
所有房间中的钥匙数量总计不超过 3000。
解法
题意:判断是否每个房间都被visited过
方法:用队列或者栈应该都可以。
class Solution(object):
def canVisitAllRooms(self, rooms):
"""
:type rooms: List[List[int]]
:rtype: bool
"""
if not rooms:
return rooms
queue = []
vis = [False for i in range(len(rooms))]
vis[0] = True
for x in rooms[0]:
queue.append(x)
vis[x] = True
while queue:
top = queue.pop(0)
for x in rooms[top]:
if vis[x] == False:
queue.append(x)
vis[x] = True
for i in range(len(vis)):
if vis[i] == False:
return False
return True
题目描述
用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
解法
开始没怎么看明白题目,所以看了题解。栈A用来作入队列。栈B用来出队列,当栈B为空时,栈A全部出栈到栈B,栈B再出栈(即出队列)。这个想法还是比较巧妙的。
# -*- coding:utf-8 -*-
class Solution:
def __init__(self):
self.stack1 = []
self.stack2 = []
def push(self, node):
# write code here
self.stack1.append(node)
def pop(self):
# return xx
if self.stack2 == []:
while self.stack1:
self.stack2.append(self.stack1.pop())
return self.stack2.pop()
定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。
注意:保证测试中不会当栈为空的时候,对栈调用pop()或者min()或者top()方法。
解法
其实就是提前存下一个min值,随时更新它就可以。
# -*- coding:utf-8 -*-
class Solution:
def __init__(self):
self.stack = []
self.mi = 100000
def push(self, node):
# write code here
self.stack.append(node)
if node < self.mi:
self.mi = node
def pop(self):
# write code here
t = self.stack[-1]
self.stack = self.stack[:-1]
if t == self.mi:
self.mi = 100000
for x in self.stack:
if x < self.mi:
self.mi = x
return t
def top(self):
# write code here
t = self.stack[-1]
return t
def min(self):
# write code here
return self.mi
请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
输出描述:
如果当前字符流没有存在出现一次的字符,返回#字符。
解法
想到了哈希,用一个列表存储所有进来的字符,随时判断每个字符是否重复,并且随时更新当前指向第一个不重复字符的指针。
但是后来看了解析,发现并不需要这么复杂,可以使用队列的思想,不需要保存下所有字符,只需要保存那些不重复的字符。
# -*- coding:utf-8 -*-
class Solution:
def __init__(self):
self.s = []
self.dic = {}
self.idx = -1
# 返回对应char
def FirstAppearingOnce(self):
# write code here
if self.idx == -1:
return "#"
return self.s[self.idx]
def Insert(self, char):
# write code here
self.s.append(char)
if char not in self.dic:
self.dic[char] = 1
if self.idx == -1:
self.idx = len(self.s) - 1
else:
self.dic[char] += 1
if self.idx != -1 and self.dic[self.s[self.idx]] > 1:
flag = 0
for i in range(self.idx + 1, len(self.s)):
if self.dic[self.s[i]] == 1:
self.idx = i
flag = 1
break
if flag == 0:
self.idx = -1
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
解法
链接:https://www.nowcoder.com/questionTerminal/d77d11405cc7470d82554cb392585106?answerType=1&f=discussion
来源:牛客网
直接模拟即可。因为弹出之前的值都会先入栈,所以这里用个栈来辅助。
# -*- coding:utf-8 -*-
class Solution:
def IsPopOrder(self, pushV, popV):
# write code here
l, r = 0, 0
stack = []
while pushV:
tmp = pushV.pop(0)
if tmp != popV[0]:
stack.append(tmp)
else:
popV.pop(0)
if not popV:
return True
while stack[-1] == popV[0]:
stack.pop(-1)
popV.pop(0)
if not popV:
return True
return False
给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则:
每次转换只能改变一个字母。
转换过程中的中间单词必须是字典中的单词。
说明:
如果不存在这样的转换序列,返回 0。
所有单词具有相同的长度。
所有单词只由小写字母组成。
字典中不存在重复的单词。
你可以假设 beginWord 和 endWord 是非空的,且二者不相同。
示例 1:
输入:
beginWord = “hit”,
endWord = “cog”,
wordList = [“hot”,“dot”,“dog”,“lot”,“log”,“cog”]
输出: 5
解释: 一个最短转换序列是 “hit” -> “hot” -> “dot” -> “dog” -> “cog”,
返回它的长度 5。
示例 2:
输入:
beginWord = “hit”
endWord = “cog”
wordList = [“hot”,“dot”,“dog”,“lot”,“log”]
输出: 0
解释: endWord “cog” 不在字典中,所以无法进行转换。
解法:
由于是求最短路径,我们很容易想到通过广度优先遍历来解决这个问题。现在我们要解决的问题就变成了如何判断两个单词只有一个字母不同。最简单的办法就是通过26个字母替换:
其他优化方法:https://blog.csdn.net/qq_17550379/article/details/83652490
class Solution(object):
def ladderLength(self, beginWord, endWord, wordList):
"""
:type beginWord: str
:type endWord: str
:type wordList: List[str]
:rtype: int
"""
wordDict = set(wordList)
if endWord not in wordList:
return 0
q = [(beginWord, 1)]
visited = set()
while q:
word, step = q.pop(0)
if word not in visited:
visited.add(word)
if word == endWord:
return step
for i in range(len(word)):
for j in 'abcdefghijklmnopqrstuvwxyz':
tmp = word[:i] + j + word[i+1:]
if tmp not in visited and tmp in wordDict:
q.append((tmp, step + 1))
return 0
给定两个单词(beginWord 和 endWord)和一个字典 wordList,找出所有从 beginWord 到 endWord 的最短转换序列。转换需遵循如下规则:
每次转换只能改变一个字母。
转换后得到的单词必须是字典中的单词。
说明:
如果不存在这样的转换序列,返回一个空列表。
所有单词具有相同的长度。
所有单词只由小写字母组成。
字典中不存在重复的单词。
你可以假设 beginWord 和 endWord 是非空的,且二者不相同。
示例 1:
输入:
beginWord = “hit”,
endWord = “cog”,
wordList = [“hot”,“dot”,“dog”,“lot”,“log”,“cog”]
输出:
[
[“hit”,“hot”,“dot”,“dog”,“cog”],
[“hit”,“hot”,“lot”,“log”,“cog”]
]
示例 2:
输入:
beginWord = “hit”
endWord = “cog”
wordList = [“hot”,“dot”,“dog”,“lot”,“log”]
输出: []
解释: endWord “cog” 不在字典中,所以不存在符合要求的转换序列。
解法
把开始单词当作开始节点,结束单词当作结束节点,现在要解决的问题就是开始节点和结束节点是否有连接,求最短路径。
首先,如果结束单词一开始就不在单词列表里,可以直接返回,因为本身就不存在这样的节点。
其次,求最短路径,最容易想到的就是BFS解法,这个从起始节点开始遍历,如果找到了结束节点,代表找到了结果,同时这个肯定是最优解(路径最短)。
注意:此时我们并不能直接返回答案,因为要求的所有最短路径,所以我们要把这一层的所有满足结果都返回。
现在我们还有2个问题:
解决方案:
BFS的时间复杂度是O(n),n代表单词列表个数,总的时间复杂度是O(26nc)。和普通BFS也没啥区别,就是2个改动,1在节点里保存了路径,2你要写一个能遍历下个节点的方法
class Solution:
def findLadders(self, beginWord, endWord, wordList):
se=set(wordList)
if not endWord in se:
return []
def edges(word):
arr=list(word)
for i in range(len(arr)):
c=arr[i]
for j in range(97,123):
arr[i]=chr(j)
newWord=''.join(arr)
if newWord in se and not newWord in marked:
yield newWord
arr[i]=c
res=[]
marked=set()
queue=[[beginWord]]
while queue:
temp=[]
found=False
for words in queue:
marked.add(words[-1])
for words in queue:
for w in edges(words[-1]):
v=words+[w]
if w == endWord:
res.append(v)
found=True
temp.append(v)
if found: #找到就不再遍历了,即使再有endWord,路径也会更长
break
queue=temp
return res
优化一:
我们可以把每个单词看作可以hash成c个值,c代表单词长度,比如单词’hit’,可以hash成’it’,'ht’,'hi*'这3个值,如果2个单词的hash值有重合,说明这2个单词是可以通过改1个字母变成另外一个的,所以我们的寻找边方法def edges(word)可以优化成这样,此方法将寻找边的O(26*c)优化成了O©
hash=collections.defaultdict(list)
for word in wordList:
for i in range(len(word)):
hash[word[:i]+"*"+word[i+1:]].append(word) #初始化:将单词列表的所有元素全部hash保存进字典
def edges(word):
for i in range(len(word)):
for newWord in hash[word[:i]+'*'+word[i+1:]]: #遍历该单词的所有hash,从字典里取出关联的单词
if not newWord in marked:
yield newWord
优化二:双向BFS
因为已经知道了开始节点和结束节点,所以可以从2头开始遍历,哪头的节点少,就遍历哪头,如果2头的节点重合了(有交集)说明连上了,遍历结束。
如果一直没交集,任何一头走到末尾就可以结束,代表全部节点都遍历完成了。
这里为了更好的取交集,begin和end都用了set来表示,同时把路径单独存储在了path字典中,一旦出现交集,从最后一个节点,依据path的存储,直到找到开始节点,能出现交集,说明一定能找到开头。
class Solution:
def findLadders(self, beginWord, endWord, wordList):
if not endWord in wordList:
return []
hash=collections.defaultdict(list)
for word in wordList:
for i in range(len(word)):
hash[word[:i]+"*"+word[i+1:]].append(word)
def edges(word):
for i in range(len(word)):
for newWord in hash[word[:i]+'*'+word[i+1:]]:
if not newWord in marked:
yield newWord
def findPath(end):
res=[]
for curr in end:
for parent in path[curr[0]]:
res.append([parent]+curr)
return res
marked=set()
path=collections.defaultdict(set)
begin=set([beginWord])
end=set([endWord])
forward=True
while begin and end:
if len(begin)>len(end):
begin,end=end,begin
forward=not forward
temp=set()
for word in begin:
marked.add(word)
for word in begin:
for w in edges(word):
temp.add(w)
if forward:
path[w].add(word)
else:
path[word].add(w)
begin=temp
if begin&end:
res=[[endWord]]
while res[0][0]!=beginWord:
res=findPath(res)
return res
return []
给定一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。
示例 1:
输入:
11110
11010
11000
00000
输出: 1
示例 2:
输入:
11000
11000
00100
00011
输出: 3
解法
标准的回溯问题:遍历整个矩阵,找到为1的就上下左右遍历,并把遍历过的设置为0,因为不会再遍历第二次(省掉visited数组).
回溯其实还可以通过队列的防止保存下来,用迭代解决。
class Solution(object):
def numIslands(self, grid):
"""
:type grid: List[List[str]]
:rtype: int
"""
if not grid:
return 0
res = 0
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j] == '1':
res += 1
self.dfs(grid, i, j)
return res
def dfs(self, grid, x, y):
grid[x][y] = '0'
if x > 0 and grid[x-1][y] == '1':
self.dfs(grid, x-1, y)
if x < len(grid) - 1 and grid[x+1][y] == '1':
self.dfs(grid, x+1, y)
if y > 0 and grid[x][y-1] == '1':
self.dfs(grid, x, y-1)
if y < len(grid[0]) - 1 and grid[x][y+1] == '1':
self.dfs(grid, x, y+1)
现在你总共有 n 门课需要选,记为 0 到 n-1。
在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1]
给定课程总量以及它们的先决条件,判断是否可能完成所有课程的学习?
示例 1:
输入: 2, [[1,0]]
输出: true
解释: 总共有 2 门课程。学习课程 1 之前,你需要完成课程 0。所以这是可能的。
示例 2:
输入: 2, [[1,0],[0,1]]
输出: false
解释: 总共有 2 门课程。学习课程 1 之前,你需要先完成课程 0;并且学习课程 0 之前,你还应先完成课程 1。这是不可能的。
说明:
输入的先决条件是由边缘列表表示的图形,而不是邻接矩阵。详情请参见图的表示法。
你可以假定输入的先决条件中没有重复的边。
提示:
这个问题相当于查找一个循环是否存在于有向图中。如果存在循环,则不存在拓扑排序,因此不可能选取所有课程进行学习。
通过 DFS 进行拓扑排序 - 一个关于Coursera的精彩视频教程(21分钟),介绍拓扑排序的基本概念。
拓扑排序也可以通过 BFS 完成。
解法
拓扑排序:在图论中,拓扑排序(Topological Sorting)是一个有向无环图(DAG, Directed Acyclic Graph)的所有顶点的线性序列。且该序列必须满足下面两个条件:
有向无环图(DAG)才有拓扑排序,非DAG图没有拓扑排序一说。
所以可以使用拓扑排序的方法,可以拓扑排序的结点数等于课程数,则表示可以完成拓扑排序,即可以完成课程。
另外一种方法:https://www.jianshu.com/p/4565fa200a62
class Solution(object):
def canFinish(self, numCourses, prerequisites):
"""
:type numCourses: int
:type prerequisites: List[List[int]]
:rtype: bool
"""
if not prerequisites:
return True
in_degree = [0 for i in range(numCourses)]
adj = [set() for i in range(numCourses)]
for x, y in prerequisites:
in_degree[x] += 1
adj[y].add(x)
q = []
for x in range(numCourses):
if in_degree[x] == 0:
q.append(x)
res = 0
while q:
tmp = q.pop(0)
res += 1
for x in adj[tmp]:
in_degree[x] -= 1
if in_degree[x] == 0:
q.append(x)
return res == numCourses
有一张picture,n个岛屿(0 ~ n-1),岛与岛之前有的有桥相连,
怎么去表示它 (n=10万);输入x,y两个岛的编号,是否可以从x岛到达y岛;怎么走?最省事的一种走法
解法
表示图的方式:邻接矩阵、邻接表、一维数组表示二维数组、链表?直接存储边?
最短路径的求法:BFS或者DFS
# 找到一条从start到end的路径
def findPath(graph,start,end,path=[]):
path = path + [start]
if start == end:
return path
for node in graph[start]:
if node not in path:
newpath = findPath(graph,node,end,path)
if newpath:
return newpath
return None
# 找到所有从start到end的路径
def findAllPath(graph,start,end,path=[]):
path = path +[start]
if start == end:
return [path]
paths = [] #存储所有路径
for node in graph[start]:
if node not in path:
newpaths = findAllPath(graph,node,end,path)
for newpath in newpaths:
paths.append(newpath)
return paths
# 查找最短路径
def findShortestPath(graph,start,end,path=[]):
path = path +[start]
if start == end:
return path
shortestPath = []
for node in graph[start]:
if node not in path:
newpath = findShortestPath(graph,node,end,path)
if newpath:
if not shortestPath or len(newpath)<len(shortestPath):
shortestPath = newpath
return shortestPath
'''
主程序
'''
graph = {'A': ['B', 'C','D'],
'B': [ 'E'],
'C': ['D','F'],
'D': ['B','E','G'],
'E': [],
'F': ['D','G'],
'G': ['E']}
onepath = findPath(graph,'A','G')
print('一条路径:',onepath)
allpath = findAllPath(graph,'A','G')
print('\n所有路径:',allpath)
shortpath = findShortestPath(graph,'A','G')
print('\n最短路径:',shortpath)
BFS:
def f3(b, x, y):
q = []
for i in b[x]:
q.append([i])
res = []
while q:
path = q.pop(0)
node = path[-1]
if node == y:
return True, path
for node in range(b[node]):
newpath = path
newpath.append(node)
q.append(newpath)
return False, None