【力扣】一处最多的同行或同列石头
作者:互联网
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/most-stones-removed-with-same-row-or-column
n 块石头放置在二维平面中的一些整数坐标点上。每个坐标点上最多只能有一块石头。
如果一块石头的 同行或者同列 上有其他石头存在,那么就可以移除这块石头。
给你一个长度为 n 的数组 stones ,其中 stones[i] = [xi, yi] 表示第 i 块石头的位置,返回 可以移除的石子 的最大数量。
示例 1:
输入:stones = [[0,0],[0,1],[1,0],[1,2],[2,1],[2,2]]
输出:5
解释:一种移除 5 块石头的方法如下所示:
1. 移除石头 [2,2] ,因为它和 [2,1] 同行。
2. 移除石头 [2,1] ,因为它和 [0,1] 同列。
3. 移除石头 [1,2] ,因为它和 [1,0] 同行。
4. 移除石头 [1,0] ,因为它和 [0,0] 同列。
5. 移除石头 [0,1] ,因为它和 [0,0] 同行。
石头 [0,0] 不能移除,因为它没有与另一块石头同行/列。
示例 2:
输入:stones = [[0,0],[0,2],[1,1],[2,0],[2,2]]
输出:3
解释:一种移除 3 块石头的方法如下所示:
1. 移除石头 [2,2] ,因为它和 [2,0] 同行。
2. 移除石头 [2,0] ,因为它和 [0,0] 同列。
3. 移除石头 [0,2] ,因为它和 [0,0] 同行。
石头 [0,0] 和 [1,1] 不能移除,因为它们没有与另一块石头同行/列。
思路并查集,把石头坐标看成图的连线,如果这些点链接起来寻找祖先,最后把字典中的祖先节点个数数一下就是不能被替换掉的节点,用总长度减去不能被换替换掉的节点个数就得答案。可惜是错的。
1 class Solution: 2 def removeStones( stones) -> int: 3 f = {} 4 n = len(stones) 5 6 def find(x): 7 f.setdefault(x, x) 8 if x != f[x]: 9 f[x] = find(f[x]) 10 return f[x] 11 12 def union(x, y): 13 f[find(y)] = find(x) 14 15 for i in range(n): 16 if find(stones[i][0]) != find(stones[i][1]): 17 union(stones[i][0], stones[i][1]) 18 print(f) 19 return n - len(set(f.values()))
正确思路:
作者:yim-6
链接:https://leetcode-cn.com/problems/most-stones-removed-with-same-row-or-column/solution/python3-bing-cha-ji-lian-jie-heng-zong-z-e3kc/
解题思路
参数定义
n:x最大取值
parent:并查集数组,存储祖先节点
root:哈希表,存储每个连通区域的根节点
思路
由于x,y所属区间为$[0,10^4]$,避免越界,可取n为10010
关键在于union(i,j+n)的理解:
1.反例:如果是union(i,j),则可能混淆i,j。如(2,4)和(4,1)不在同行同列,而通过union(i,j)后就成了一个连通区域。
2.如图union(i,j+n),示例(0,0)和(2,0)会指向10010,而(0,2)和(2,2)会指向10012,而由于连通性,(2,0)和(2,2)有着相同的横坐标,所以10010指向10012
遍历stones中的x坐标,可以找到两个连通区域的根节点:10011和10012
返回值即为:石头总数-连通区域个数
复杂度分析
时间复杂度:O(Mα(M)),M为石头数量,α(M)为路径压缩时间
空间复杂度:O(N),parent的大小
1 class Solution: 2 def removeStones(self, stones: List[List[int]]) -> int: 3 n=10010 4 parent=list(range(2*n)) 5 # 并查集查找 6 def find(x): 7 if x!=parent[x]: 8 parent[x]=find(parent[x]) 9 return parent[x] 10 # 合并 11 def union(i,j): 12 parent[find(i)]=find(j) 13 # 连通横纵坐标 14 for i,j in stones: 15 union(i,j+n) 16 # 获取连通区域的根节点 17 root=set() 18 for i,j in stones: 19 root.add(find(i)) 20 return len(stones)-len(root) 21 22 作者:yim-6 23 链接:https://leetcode-cn.com/problems/most-stones-removed-with-same-row-or-column/solution/python3-bing-cha-ji-lian-jie-heng-zong-z-e3kc/ 24 来源:力扣(LeetCode)
DFS解法:
作者:heimisa000
链接:https://leetcode-cn.com/problems/most-stones-removed-with-same-row-or-column/solution/pythondfsjie-fa-yong-shi-jin-wei-68msda-liang-zhu-/
1. 思路:
1.1 题目分析:
首先吐槽一下题目,我左看右看也没看懂-_-||
题目含义是:如果想移除一个石头,那么它所在的行或者列必须有其他石头存在。我们能移除的最多石头数是多少?
也就是说,只有一个石头在连通分量中,才能被移除。对于连通分量而言,最理想的状态是只剩一块石头。对于任何容量为n一个连通分量,可以移除的石头数都为n-1。
那么问题就被转化为:
这些石头可以构成多少个连通分量,每个分量中有多少块石头?
进一步地,由于题目中强调了,每个坐标点最多只能有一块石头,也就是说给定的stones列表中没有重复坐标,总石头数等于stones列表的长度。而每个连通分量最后都会剩下一块石头,所以:
可以移走的石头数 = 总石头数 - 剩余石头数 = stones列表长度 - 连通分量个数
1.2 连通分量计算:
事实上,连通分量计算最好的办法是并查集,可是我们这里偏要勉强,用DFS解法计算(实际上是渣渣并不懂并查集 ̄□ ̄||)。
值得注意的是,连通的条件是:两个点在同一行或者同一列,为了保存行和列信息,我们用两个set进行记录,即row和col。剩余部分与其他连通分量计算的题大同小异,详见代码。
1 class Solution: 2 def removeStones(self, stones: List[List[int]]) -> int: 3 m = 0 # 记录最大的行坐标 4 row = collections.defaultdict(set) # 记录每一行中点的列坐标 5 col = collections.defaultdict(set) # 记录每一列中点的行坐标 6 7 for i,j in stones: # 遍历所有石头坐标 8 row[i] |= {j} # 记录行对应的列坐标 9 col[j] |= {i} # 记录列对应的坐标 10 m = max(m,i) # 记录最大的行坐标 11 12 13 graph = 0 # 连通分量的个数 14 15 for i in range(m+1): # 对于所有的i进行遍历 16 if i in row: # 如果i在row中,即i对一个新的连通分量 17 graph += 1 # 连通分量数 +1 18 stack = {i} # 这里用set模拟栈,方便后面合并操作 19 20 while stack: # 栈非空时 21 x = stack.pop() # 从栈中不断弹出行坐标x 22 for j in row[x]: # 对于row[x]中所保存的所有列坐标j 23 if j in col: # 如果col[j]非空,说明该列有对应的行 24 # 可以和当前行x构成连通分量 25 stack |= col[j] # 将col[j]中所有的行合并到栈中 26 del col[j] # 并删除col[j],防止循环调用 27 28 del row[x] # 最后删除row[x],防止循环调用 29 30 return len(stones) - graph # 针对于每个连通分量,最后只剩一个石子 31 # 因此剩余石子个数为连通分量个数graph 32 # 由于石子坐标是唯一的 33 # 因此总石子个数为stones的长度 34 # 可操作数为总石子数 - 剩余石子数 35 # 即 len(stones) - graph 36 37 38 作者:heimisa000 39 链接:https://leetcode-cn.com/problems/most-stones-removed-with-same-row-or-column/solution/pythondfsjie-fa-yong-shi-jin-wei-68msda-liang-zhu-/ 40 来源:力扣(LeetCode)
标签:stones,连通,同行,石头,力扣,同列,坐标,移除,row 来源: https://www.cnblogs.com/Harukaze/p/14281456.html