1. 程式人生 > >【LeetCode】947. Most Stones Removed with Same Row or Column 解題報告(Python & C++)

【LeetCode】947. Most Stones Removed with Same Row or Column 解題報告(Python & C++)

作者: 負雪明燭
id: fuxuemingzhu
個人部落格: http://fuxuemingzhu.cn/


目錄

題目地址:https://leetcode.com/problems/most-stones-removed-with-same-row-or-column/description/

題目描述

On a 2D plane, we place stones at some integer coordinate points. Each coordinate point may have at most one stone.

Now, a move consists of removing a stone that shares a column or row with another stone on the grid.

What is the largest possible number of moves we can make?

Example 1:

Input: stones = [[0,0],[0,1],[1,0],[1,2],[2,1],[2,2]]
Output: 5

Example 2:

Input: stones = [[0,0],[0,2],[1,1],[2,0],[2,2]]
Output: 3

Example 3:

Input: stones = [[0,0]]
Output: 0

Note:

  1. 1 <= stones.length <= 1000
  2. 0 <= stones[i][j] < 10000

題目大意

在二維座標的整數座標點上,有一些石頭,如果一個石頭和另外一個石頭的橫座標或者縱座標相等,那麼認為他們是有連結的。我們每次取一個和別人有連結的石頭,問最終能取得多少個石頭。

解題方法

並查集

這個題翻譯一下就是,橫或者縱座標相等的座標點會互相連結構成一個區域,問總的有多少個獨立的區域。結果是總的石頭數減去獨立區域數。

所以,我們根本不用考慮太多,只需要統計有多少區域即可。這個方法最簡單的就是並查集。

思路是,兩重迴圈,分別判斷石頭兩兩之間是否有連結,如果有連結,那麼把他們組成同一個區域。這樣的優點是我們只需要和石頭等長的陣列放每個的parent即可。最後統計最後的區域中-1的數量就是獨立區域的個數。石頭個數減去獨立區域數即可。

python程式碼如下,可惜超時了。

class Solution(object):
    def removeStones(self, stones):
        """
        :type stones: List[List[int]]
        :rtype: int
        """
        N = len(stones)
        self.map = [-1] * N
        for i in range(N):
            for j in range(i + 1, N):
                if stones[i][0] == stones[j][0] or stones[i][1] == stones[j][1]:
                    self.union(i, j)
        res = N
        print(self.map)
        for i in range(N):
            if self.map[i] == -1:
                res -= 1
        return res
        
    def find(self, x):
        return x if self.map[x] == -1 else self.find(self.map[x])
        
    def union(self, x, y):
        fx = self.find(x)
        fy = self.find(y)
        if fx != fy:
            self.map[fx] = fy

這個版本的C++可以做通過,說明了C++速度的優越性。

class Solution {
public:
    int removeStones(vector<vector<int>>& stones) {
        if(stones.size() <= 1) return 0;
        int N = stones.size();
        vector<int> p(N, -1);
        for (int i = 0; i < N; ++i){
            for(int j = i + 1; j < N; ++j){
                if (stones[i][0] == stones[j][0] || stones[i][1] == stones[j][1]){
                    u(p, i, j);
                }
            }
        }
        int res = N;
        for(auto e: p) if(e == -1) --res;
        return res;
    }
private:
    int f(vector<int> &p, int x){
        if(p[x] == -1) return x;
        return f(p, p[x]);
    }
    
    void u(vector<int> &p, int x, int y){
        int px = f(p, x);
        int py = f(p, y);
        if(px != py){
            p[px] = py;
        }
    }
};

其實上面這個版本可以做優化,我們不用對石頭進行兩兩判斷,而是對他們的橫縱座標同等看待。怎麼區分橫縱座標呢?使用的方法是把縱座標+10000,這樣行的索引沒變,縱座標的範圍跑到了後面去了。

這個做法的思路是,一個座標其實就是把橫縱座標對應的兩個區域進行了連結。所以,只需要對stones進行一次遍歷把對應的區域連結到一起即可。在完成連結之後,我們最後統計一下有多少個獨立的區域,需要使用set+find。

Python程式碼如下:

class Solution(object):
    def removeStones(self, stones):
        """
        :type stones: List[List[int]]
        :rtype: int
        """
        N = len(stones)
        self.map = [-1] * 20000
        for x, y in stones:
            self.union(x, y + 10000)
        count = set()
        return N - len({self.find(x) for x, y in stones})
        
    def find(self, x):
        return x if self.map[x] == -1 else self.find(self.map[x])
        
    def union(self, x, y):
        fx = self.find(x)
        fy = self.find(y)
        if fx != fy:
            self.map[fx] = fy

C++程式碼如下:

class Solution {
public:
    int removeStones(vector<vector<int>>& stones) {
        if(stones.size() <= 1) return 0;
        int N = stones.size();
        vector<int> p(20000, -1);
        for(auto stone : stones){
            u(p, stone[0], stone[1] + 10000);
        }
        set<int> parents;
        for(auto stone : stones){
            parents.insert(f(p, stone[0]));
        }
        return N - parents.size();
    }
private:
    int f(vector<int> &p, int x){
        if(p[x] == -1) return x;
        return f(p, p[x]);
    }
    
    void u(vector<int> &p, int x, int y){
        int px = f(p, x);
        int py = f(p, y);
        if(px != py){
            p[px] = py;
        }
    }
};

日期

2018 年 11 月 24 日 —— 週日開始!一週就過去了~