前言
本篇章所涉及到的题目均来源于力扣(LeetCode),著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
LeetCode中有关图的题目。
1. LeetCode684:冗余连接
LeetCode第684题:冗余连接。
题目
在本问题中, 树指的是一个连通且无环的无向图。
输入一个图,该图由一个有着 N N N个节点 ( ( (节点值不重复 1 , 2 , . . . , N ) 1, 2, ..., N) 1,2,...,N)的树及一条附加的边构成。附加的边的两个顶点包含在 1 1 1到 N N N中间,这条附加的边不属于树中已存在的边。
结果图是一个以边组成的二维数组。每一个边的元素是一对 [ u , v ] [u, v] [u,v],满足 u < v u < v u<v,表示连接顶点 u u u和 v v v的无向图的边。
返回一条可以删去的边,使得结果图是一个有着 N N N个节点的树。如果有多个答案,则返回二维数组中最后出现的边。答案边 [ u , v ] [u, v] [u,v]应满足相同的格式 u < v u < v u<v。
注意
(1) 输入的二维数组大小在 3 3 3到 1000 1000 1000。
(2) 二维数组中的整数在 1 1 1到 N N N之间,其中 N N N是输入数组的大小。
解题思路
这个题可以当做并查集来做,思路就是检查每一条边上两个顶点是否在一个集合中,如果在,那么加入这条边之后图中就会构成环;如果不在,就让它并入集合中。
有关并查集的知识及操作请参阅这篇博客。
代码实现如下:
def Find(self, S, x):
while S[x] != -1:
x = S[x]
return x
def Union(self, S, root1, root2, result):
# 这里的减一是因为我设置的S是从0开始的
x = self.Find(S, root1-1)
y = self.Find(S, root2-1)
if x != y:
S[y] = x
else:
result.append([root1, root2])
def findRedundantConnection(self, edges):
length = len(edges)
S = [-1] * length
result = []
for i, j in edges:
self.Union(S, i, j, result)
return result[-1]
运行结果如下:
2. LeetCode841:钥匙和房间
LeetCode第841题:钥匙和房间。
题目
有 N N N个房间,开始时你位于 0 0 0号房间。每个房间有不同的号码: 0 , 1 , 2 , . . . , N − 1 0,1,2,...,N-1 0,1,2,...,N−1,并且房间里可能有一些钥匙能使你进入下一个房间。在形式上,对于每个房间 i i i都有一个钥匙列表 r o o m s [ i ] rooms[i] rooms[i],每个钥匙 r o o m s [ i ] [ j ] rooms[i][j] rooms[i][j]由 [ 0 , 1 , . . . , N − 1 ] [0,1,...,N-1] [0,1,...,N−1]中的一个整数表示,其中 N = r o o m s . l e n g t h N = rooms.length N=rooms.length。 钥匙 r o o m s [ i ] [ j ] = v rooms[i][j] = v rooms[i][j]=v可以打开编号为 v v v的房间。
最初,除 0 号房间外的其余所有房间都被锁住。你可以自由地在房间之间来回走动。如果能进入每个房间返回 t r u e true true,否则返回 f a l s e false false。
提示
1. 1 <= rooms.length <= 1000
2. 0 <= rooms[i].length <= 1000
3. 所有房间中的钥匙数量总计不超过 3000。
解题思路
这个题可以将房间看成图中的顶点,而房间里的钥匙则是连接另个一个顶点的弧,没错,是个有向图。所以这个问题的本质就是图的遍历,如果遍历一次结束,顶点全部被访问过,即能进入每个房间,返回 t r u e true true,否则就返回 f a l s e false false。
有关图遍历的操作,请参阅我的这篇博客。
深度优先遍历代码实现如下:
def canVisitAllRooms(self, rooms):
self.rooms = rooms
length = len(rooms)
visited = [False] * length
self.DFS(visited, v=0)
if len(set(visited)) == 1:
return True
else:
return False
def DFS(self, visited, v):
visited[v] = True
for k in self.rooms[v]:
# k是房间v里面的钥匙
if not visited[k]:
self.DFS(visited, k)
运行结果如下:
广度优先遍历代码实现如下:
def canVisitAllRooms(self, rooms):
import collections
self.rooms = rooms
length = len(rooms)
visited = [False] * length
visited[0] = True
# 把房间0加入队列
queue = collections.deque(iterable=[0])
self.BFS(visited, queue)
if len(set(visited)) == 1:
return True
else:
return False
def BFS(self, visited, queue):
while queue:
v = queue.popleft()
for k in self.rooms[v]:
# k是房间v里面的钥匙
if not visited[k]:
visited[k] = True
queue.append(k)
运行结果如下:
3. LeetCode1387:将整数按权重排序
LeetCode第1387题:将整数按权重排序。
题目
我们将整数 x x x 的 权重 定义为按照下述规则将 x x x 变成 1 1 1 所需要的步数:
如果 x x x 是偶数,那么 x = x / 2 x = x / 2 x=x/2
如果 x x x 是奇数,那么 x = 3 ∗ x + 1 x = 3 * x + 1 x=3∗x+1
比方说, x = 3 x=3 x=3 的权重为 7 7 7 。因为 3 3 3 需要 7 7 7 步变成 1 ( 3 − − > 10 − − > 5 − − > 16 − − > 8 − − > 4 − − > 2 − − > 1 ) 1 (3 --> 10 --> 5 --> 16 --> 8 --> 4 --> 2 --> 1) 1(3−−>10−−>5−−>16−−>8−−>4−−>2−−>1)。
给你三个整数 l o lo lo, h i hi hi 和 k k k 。你的任务是将区间 [ l o , h i ] [lo, hi] [lo,hi] 之间的整数按照它们的权重 升序排序 ,如果大于等于 2 2 2 个整数有 相同 的权重,那么按照数字自身的数值 升序排序 。
请你返回区间 [ l o , h i ] [lo, hi] [lo,hi] 之间的整数按权重排序后的第 k k k 个数。
注意
题目保证对于任意整数 x ( l o < = x < = h i ) x (lo <= x <= hi) x(lo<=x<=hi) ,它变成 1 1 1 所需要的步数是一个 32 32 32 位有符号整数。
提示
1. 1 <= lo <= hi <= 1000
2. 1 <= k <= hi - lo + 1
解题思路
这个题可以把它当做图,用深度优先遍历来做。就是把区间里的整数看成图中的顶点,用 R R R表示吧,计算每个 R R R的权重的过程又可以看成遍历图的过程,我举个栗子,就是下面这张图,对应着示例 1
:
大致就是这么个意思,哈哈哈哈(ノ´▽`)ノ♪
代码实现如下:
def DFS(self, x):
if x == 1:
# 递归结束条件
return 0
# 统计步数
elif x % 2 == 0:
# 偶数
return self.DFS(x / 2) + 1
elif x % 2 != 0:
# 奇数
return self.DFS(3 * x + 1) + 1
def getKth(self, lo, hi, k):
result = []
for x in range(lo, hi+1):
count = self.DFS(x)
result.append([x, count])
result = sorted(result, key=lambda item: item[1])
return result[k-1][0]
运行结果如下:
时间消耗较多,勉强算是跑完了ヾ(@^▽^@)ノ
4. LeetCode997:找到小镇的法官
LeetCode第997题:找到小镇的法官。
题目
在一个小镇里,按从 1 1 1 到 N N N 标记了 N N N 个人。传言称,这些人中有一个是小镇上的秘密法官。
如果小镇的法官真的存在,那么:
- 小镇的法官不相信任何人。
- 每个人(除了小镇法官外)都信任小镇的法官。
- 只有一个人同时满足属性 1 1 1 和属性 2 2 2。
给定数组 t r u s t trust trust,该数组由信任对 t r u s t [ i ] = [ a , b ] trust[i] = [a, b] trust[i]=[a,b] 组成,表示标记为 a a a 的人信任标记为 b b b 的人。
如果小镇存在秘密法官并且可以确定他的身份,请返回该法官的标记。否则,返回 − 1 -1 −1。
提示
1. 1 <= N <= 1000
2. trust.length <= 10000
3. trust[i] 是完全不同的
4. trust[i][0] != trust[i][1]
5. 1 <= trust[i][0], trust[i][1] <= N
解题思路
画了一个图可以发现,这个题可以用有向图来做,即把每个人当做图中的顶点,如果 P e r s o n 1 Person1 Person1信任 P e r s o n 2 Person2 Person2,则 P e r s o n 1 Person1 Person1是弧尾, P e r s o n 2 Person2 Person2是弧头,由题目可知,所有人都信任法官,即法官所在顶点的入度为 N − 1 N-1 N−1,法官不信任任何人,即法官所在顶点的出度为 0 0 0。
代码实现如下:
def findJudge(self, N, trust):
indegree = [0] * N
outdegree = [0] * N
for i, j in trust:
outdegree[i-1] += 1
indegree[j-1] += 1
for index in range(N):
if indegree[index] == N-1 and outdegree[index] == 0:
return index + 1
return -1
运行结果如下: