778. 水位上升的泳池中游泳(DFS+二分)

這個題目,用搜索做是很正常的想法 ,於是我就這樣交代碼了;
由於題給測試數據不大,200ms還是過了。

時間複雜度:O(n4)O(n^4)

const int dx[] = {-1,0,1,0};
const int dy[] = {0,1,0,-1};

class Solution {
public:
    int n,t;
    bool vis[51][51];
    int swimInWater(vector<vector<int>>& grid) {
        n=grid.size();
        for(t=0;t<n*n;t++){
            if(grid[0][0]<=t){
                memset(vis,0,sizeof(vis)); //每次dfs,都要刷新一下
                if(dfs(0,0,grid)){
                    return t;
                }
            }
        }
        return n*n-1;
    }
    bool dfs(int x,int y,vector<vector<int>>& grid){
        // cout<<x<<"  "<<y<<endl;
        if(x==n-1 && y==n-1){
            return true;
        }
        vis[x][y] = 1;
        for(int k=0;k<4;k++){
            int nx = x + dx[k];
            int ny = y + dy[k];
            if(nx>=0&&ny>=0&&nx<n&&ny<n && grid[nx][ny]<=t && !vis[nx][ny]){
                if(dfs(nx,ny,grid)){
                    return true;
                }
	 // vis[nx,ny] = 0;這個地方不需要也不能還原現場,否則會冗餘搜索。
            }
        }
        return false;
    }
};

然後是怎麼想到二分的呢?dfs()是一個關於時間t的函數,返回true 或false,相當於是在[1,n*n-1]這個區間猜一個數,剛好處於一個臨界點(超過這個臨界點都是true,不到臨界點都是false)。
這不就是一個二分應用裏面的一個猜大小數字的小遊戲嗎?
dfs(t)={01,t[1,n21]dfs(t)=\begin{cases} 0\\ 1 \end{cases} ,t\in [1,n^2-1]

時間複雜度O(log(n2)n2)=O(log(n)n2)O(log(n^2)*n^2)=O(log(n)n^2)

const int dx[] = {-1,0,1,0};
const int dy[] = {0,1,0,-1};

class Solution {
public:
    int n;
    bool vis[51][51];
    int swimInWater(vector<vector<int>>& grid) {
        n=grid.size();
        int l = grid[0][0], r = n*n-1,mid;
        while(l<r){
            int mid = (l+r)/2;
            memset(vis,0,sizeof(vis));
            if(dfs(0,0,mid,grid)){
                r = mid;
            }else{
                l = mid +1;
            }
        }
        return l;
    }
    bool dfs(int x,int y,int t,vector<vector<int>>& grid){
        if(x==n-1 && y==n-1){
            return true;
        }
        vis[x][y] = 1;
        for(int k=0;k<4;k++){
            int nx = x + dx[k];
            int ny = y + dy[k];
            if(nx>=0&&ny>=0&&nx<n&&ny<n && grid[nx][ny]<=t && !vis[nx][ny]){
                if(dfs(nx,ny,t,grid)){
                    return true;
                }
                // vis[nx][ny] = 0;
            }
        }
        return false;
    }

};

這裏,我也用並查集做了一下,原理是一樣的。

const int dx[] = {-1,0,1,0};
const int dy[] = {0,1,0,-1};
struct UFS{
    int f[50*50+10];
    UFS(){
        for(int i=0;i<50*50+10;i++){
            f[i]=i;
        }
    }
    int find(int x){
        return x==f[x]?x:f[x]=find(f[x]);
    }
    void merge(int x,int y){
        f[find(x)] = find(y);
    }
};
class Solution {
public:
    int swimInWater(vector<vector<int>>& grid) {
        int n = grid.size(),t;
        int l= grid[0][0],r=n*n-1;
        while(l<r){
            int mid = (l+r)/2;
            UFS ufs;
            for(int x=0;x<n;x++){
                for(int y=0;y<n;y++){
                    if(grid[x][y]>mid){
                        continue;
                    }
                    for(int k=0;k<4;k++){
                        int nx = x + dx[k];
                        int ny = y + dy[k];
                        if(nx>=0 && ny>=0 && nx<n && ny<n && grid[nx][ny]<=mid){
                            ufs.merge(x*50+y,nx*50+ny);
                        }
                    }
                }
            }
            if(ufs.find(0)==ufs.find((n-1)*50+(n-1))){
                r = mid;
            }else{
                l = mid+1;
            }
        }
        return l;
    }
};

這題還有用優先隊列做的,暫時先擱着吧。
以後再補。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章