1
0
mirror of https://github.com/SunnyQjm/algorithm-review.git synced 2026-06-03 08:16:43 +08:00

add: chapter12

This commit is contained in:
2020-06-22 18:40:13 +08:00
parent 6bb6556d34
commit 0e1b67a419
3 changed files with 209 additions and 0 deletions
@@ -0,0 +1,62 @@
#!/usr/bin/env python
# coding=utf-8
#######################################################################################
# Leetcode 787 K 站中转内最便宜的航班
#
# 题目太长了,瞅这 => https://leetcode-cn.com/problems/cheapest-flights-within-k-stops/
#######################################################################################
from typing import List
import collections, heapq
class Solution:
def findCheapestPrice(self, n: int, flights: List[List[int]], src: int, dst: int, K: int) -> int:
"""
:type n: int 城市个数
:type flights: List[List[int]] m个航班
:type src: int 出发城市
:type dst: int 到达城市
:type K: int 最大中转次数
:rtype int
(knowledge)
思路:
1. 执行Djikstra算法计算最短距离的算法,过程中传递当前的跳数,当跳数超过k+1时进行剪枝;
2. 使用最小堆来简化Djikstra代码实现;
3. 过程中一旦遍历到目的节点,就返回;
"""
# 这边使用字典来统一表示图
graph = collections.defaultdict(dict)
# 构建图
for u, v, w in flights:
graph[u][v] = w
# 最小堆中的每个元素为一个三元组,<源节点到当前节点的开销,源节点到当前节点走了几跳,当前节点编号>
pq = [(0, 0, src)]
while pq:
# 从最小堆中取出cost最小的元素
cost, step, place = heapq.heappop(pq)
# 如果到达当前节点的跳数大于K+1,则跳过
if step > K + 1:
continue
if place == dst:
return cost
# 遍历当前节点的所有邻居
for neighbour, weight in graph[place].items():
heapq.heappush(pq, (cost + weight, step + 1, neighbour))
return -1
if __name__ == '__main__':
solution = Solution()
print(solution.findCheapestPrice(3, [[0, 1, 100], [1, 2, 100], [0, 2, 500]], 0, 2, 1), "= 200")
print(solution.findCheapestPrice(3, [[0, 1, 100], [1, 2, 100], [0, 2, 500]], 0, 2, 0), "= 500")
+92
View File
@@ -0,0 +1,92 @@
#!/usr/bin/env python
# coding=utf-8
#######################################################################################
# Leetcode 934 最短的桥
#
# 在给定的二维二进制数组 A 中,存在两座岛。(岛是由四面相连的 1 形成的一个最大组。)
# 现在,我们可以将 0 变为 1,以使两座岛连接起来,变成一座岛。
# 返回必须翻转的 0 的最小数目。(可以保证答案至少是 1。)
#
# 示例 1
# 输入:[[0,1],[1,0]]
# 输出:1
#
# 示例 2
# 输入:[[0,1,0],[0,0,0],[0,0,1]]
# 输出:2
#
# 示例 3
# 输入:[[1,1,1,1,1],[1,0,0,0,1],[1,0,1,0,1],[1,0,0,0,1],[1,1,1,1,1]]
# 输出:1
#
# 提示:
# 1. 1 <= A.length = A[0].length <= 100
# 2. A[i][j] == 0 或 A[i][j] == 1
#######################################################################################
from typing import List
class Solution:
def shortestBridge(self, A: List[List[int]]) -> int:
"""
:type A: List[List[int]]
:rtype int
(knowledge)
思路:
1. 首先使用DFS的方式找到其中一座岛屿,并将该岛屿内所有块标记为2;
2. 接着使用BFS的方式逐层向外探索:
- 超出边界则忽略;
- 探索到海域,则将其标记为2,表示已经探索过;
- 当探索到1即终止,返回当前的轮数
"""
n, queue = len(A), []
def dfs(i, j, queue):
if i < 0 or j < 0 or i >= n or j >= n or A[i][j] != 1:
return
A[i][j] = 2
queue.append((i, j))
dfs(i - 1, j, queue)
dfs(i + 1, j, queue)
dfs(i, j - 1, queue)
dfs(i, j + 1, queue)
return
# 通过dfs找到第一座岛屿
find = False
for i in range(n):
for j in range(n):
if A[i][j] == 1:
dfs(i, j, queue)
find = True
break
if find:
break
# 通过BFS搜索另一个岛屿
s = 0 # 轮数
while queue:
for _ in range(len(queue)):
i, j = queue.pop(0)
for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
x, y = i + dx, j + dy
if x < 0 or y < 0 or x >= n or y >= n or A[x][y] == 2:
continue
if A[x][y] == 1:
return s
# 经过海域,则将其标记为2,表示已经探索过
A[x][y] = 2
queue.append((x, y))
s += 1
if __name__ == '__main__':
solution = Solution()
print(solution.shortestBridge([[0 ,1], [1, 0]]), "= 1")
print(solution.shortestBridge([[0 ,1, 0], [0, 0, 0], [0, 0, 1]]), "= 2")
print(solution.shortestBridge([[1, 1, 1, 1, 1], [1, 0, 0, 0, 1], [1, 0, 1, 0, 1], [1, 0, 0, 0, 1], [1, 1, 1, 1, 1]]), "= 1")
+55
View File
@@ -0,0 +1,55 @@
#!/usr/bin/env python
# coding=utf-8
#######################################################################################
# Leetcode 692 前K个高频单词
#
# 给一非空的单词列表,返回前 k 个出现次数最多的单词。
# 返回的答案应该按单词出现频率由高到低排序。如果不同的单词有相同出现频率,按字母顺序排序。
#
# 示例 1
# 输入: ["i", "love", "leetcode", "i", "love", "coding"], k = 2
# 输出: ["i", "love"]
# 解析: "i" 和 "love" 为出现次数最多的两个单词,均为2次。
# 注意,按字母顺序 "i" 在 "love" 之前。
#
# 示例 2
# 输入: ["the", "day", "is", "sunny", "the", "the", "the", "sunny", "is", "is"], k = 4
# 输出: ["the", "is", "sunny", "day"]
# 解析: "the", "is", "sunny" 和 "day" 是出现次数最多的四个单词,
# 出现次数依次为 4, 3, 2 和 1 次。
#
# 注意:
# 1. 假定 k 总为有效值, 1 ≤ k ≤ 集合元素数。
# 2. 输入的单词均由小写字母组成。
#
# 扩展练习:
# 尝试以 O(n log k) 时间复杂度和 O(n) 空间复杂度解决。
#######################################################################################
from typing import List
import collections
class Solution:
def topKFrequent(self, words: List[str], k: int) -> List[str]:
"""
:type words: List[str]
:type k: int
:rtype List[str]
(knowledge)
思路:
1. 统计每个单词出现的频率;
2. 然后按照词频和字母序排序(首先按照词频排序,然后如果词频相同就按字母序排序);
3. 最后返回排序后前k个元素
"""
count = collections.Counter(words)
candidates = list(count.keys())
candidates.sort(key=lambda w: (-count[w], w))
return candidates[:k]
if __name__ == '__main__':
solution = Solution()
print(solution.topKFrequent(["i", "love", "leetcode", "i", "love", "coding"], 2), "= [\"i\", \"love\"]")