移除最多的同行或同列石头

947. 移除最多的同行或同列石头

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]不能移除,因为它没有与另一块石头同行/列。

解答这道题核心就是: 需要统计所给出的所有点可以分成多少组的查并集, 而每一个查并集都可以最终只保留一个, 而总点数 - 查并集数量 就是返回的结果了.
所给出的两种方案 思路都是一样的, 区别在于, 一个全量初始化节点, 一个每次用到的时候才会去初始化节点, 优点在于当有一个比较长的列表来计算节点时 会节省时间和内存.

# 88ms  15MB
def removeStones(stones):
    n = 10010
    father = {}

    def getFaterValue(x):
        if x not in father:
            father[x] = x
            return x
        return father[x]

    def find(x):
        if x != getFaterValue(x):
            father[x] = find(getFaterValue(x))
        return father[x]

    def merge(x, y):
        father[find(x)] = find(y)

    for x, y in stones:
        merge(x, y + 10010)

    res = set()
    for x, _ in stones:
        res.add(find(x))

    return len(stones) - len(res)

# 下面方法虽然简洁 但是内存过大  180ms 49.3MB
def other(stones):
    n = 10010
    father = {x: x for x in range(n * 2)}

    def find(x):
        if x != father[x]:
            father[x] = find(father[x])
        return father[x]

    def merge(x, y):
        father[find(x)] = find(y)

    for x, y in stones:
        merge(x, y + n)
    res = set()
    for x, _ in stones:
        res.add(find(x))

    return len(stones) - len(res)

stones = [[0,0],[0,1],[1,0],[1,2],[2,1],[2,2]]
print(removeStones(stones)) # 5
print(other(stones)) # 5

stones = [[1,2],[1,3],[3,3],[3,1],[2,1],[1,0]]
print(removeStones(stones)) # 5
print(other(stones)) # 5
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这道题目可以使用二分答案的思想来解决。首先,我们可以确定一个最小距离的下界,即首尾两块石头之间的距离除以m+1,因为最多移除m块石头,所以剩下的石头之间的距离至少为这个值。然后,我们可以二分一个最小距离的上界,然后判断是否能够移除m块石头,使得相邻两块石头之间的距离都大于等于这个最小距离。如果可以,那么我们可以继续往上二分,否则就往下二分,直到找到最大的最小距离。 ### 回答2: 这道问题涉及到的知识点是贪心算法,通过贪心策略找到最优解。 首先需要明确的是,移除石头的数量越多,留下的石头之间的距离就会越大,相邻石头之间的距离的最小值就会越小;反之,移除石头越少,相邻石头之间的距离的最小值就会越大。 因此,我们需要寻找一个最优的移除石头数量,使得相邻石头之间的距离的最小值最大。为了达到这个目标,我们可以使用二分查找来确定移除石头数量,二分查找的上下界分别是1和石头的总数量减去2(首尾两块石头不能被移除)。 在每一次查找中,我们需要判断是否存在一种方案可以移除m块石头后,相邻石头之间的距离的最小值大于等于当前二分值mid。为了达到这个目标,我们可以从链的起点开始,逐个查找石头,如果两个相邻石头之间的距离小于mid,则移除其中一个石头,直到没有可以移除石头为止。 如果在移除m块石头后,相邻石头之间的距离的最小值大于等于mid,则表示当前二分值可以满足题目条件,我们需要继续查找更大的二分值;否则,我们需要查找更小的二分值。最终,二分查找结束后,找到的就是最大的相邻石头之间距离的最小值。 总之,这道问题的解法是贪心算法+二分查找,通过寻找最优的移除石头数量来达到相邻石头之间距离的最小值最大。 ### 回答3: 题目分析: 这个问题可以看作是一个二分答案的问题,即我们可以二分答案得到最大的相邻两块石头之间的距离。然后判断在这个距离前提下,是否可以移除 m 块石头。如果可以,则说明最大距离偏小,我们应该让最大距离增大;否则说明最大距离偏大,我们应该让最大距离减小。 具体实现: - 对给定的相邻两块石头之间的距离进行排序,我们可以使用 STL 中的 sort 函数进行排序。 - 判断这个最小值为 val 时,能否移除 m 块石头。因为首尾两块石头不能移除,所以可以从第二块石头开始进行贪心,只要有连续的 m+1 块石头距离都小于等于 val,就选择移除第 m+1 块石头。 - 最后我们可以进行二分答案,在搜索的过程中,如果在 val 下可以移除 m 块石头,则说明答案可以更大;反之则说明答案应该更小。 代码实现: ```C++ #include <algorithm> #include <iostream> using namespace std; const int N = 1e5 + 5; int n, m; int dist[N], diff[N]; bool check(int mid) { int cnt = 0; for (int i = 1, j = 1; i <= n; j = i) { while (j + 1 <= n && dist[j + 1] - dist[i] <= mid) ++j; if (j == i) return false; if (i != 1 || j != n) ++cnt; i = j + 1; } return cnt <= m; } int main() { cin >> n >> m; for (int i = 1; i <= n; ++i) cin >> dist[i]; sort(dist + 1, dist + n + 1); for (int i = 2; i <= n; ++i) diff[i - 1] = dist[i] - dist[i - 1]; int l = 0, r = 1e9 + 1; while (r - l > 1) { int mid = (l + r) / 2; if (check(mid)) l = mid; else r = mid; } cout << l << endl; return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值