力扣5845. 你能穿过矩阵的最后一天

力扣 5845. 你能穿过矩阵的最后一天
https://leetcode-cn.com/problems/last-day-where-you-can-still-cross/

解析:
二分广搜
因为以最后一天可联通为分界线,前面的日子都是可以从第一行到最后一行的,后面的不可以,所以可以二分以第几天为分界线。
复杂度 O(n2logn)

class Solution {
public:
    int latestDayToCross(int row, int col, vector<vector<int>>& cells) {
        int l = 1,r = row * col;
        while(l < r){
            int mid = (l + r + 1) >> 1;
            if(ck(mid, row, col, cells)) l = mid;
            else r = mid - 1;
        }
        return l;
    }

    bool ck(int n,int row,int col,vector<vector<int>>& cells){
        vector<vector<int>> g(row,vector<int>(col,1));
        int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
        for(int i=0;i<n;i++){
            int x = cells[i][0],y = cells[i][1];
            g[x-1][y-1] = 0;
        }
        queue<pair<int,int>> q;
        for(int i=0;i<col;i++){
            if(g[0][i]){
                q.push({0,i});
                g[0][i] = 0;
            }
        }
        while(q.size()){
            auto t = q.front();q.pop();
            int x = t.first,y = t.second;
            if(x == row - 1) return true;

            for(int i=0;i<4;i++){
                int nx = x + dx[i];
                int ny = y + dy[i];
                if(nx < 0 || nx >= row || ny < 0 || ny >= col) continue;
                if(g[nx][ny] == 0) continue;
                g[nx][ny] = 0;
                q.push({nx,ny});
            }
        }
        return false;
    }
};

从后往前推+并查集
从后往前,如果如果当前结点四个方向中某个方向在集合里了,就将他们连接起来
定义两个超级结点,第一个算作连接第一行的所有结点,第二个算作连接最后一行的所有结点。
如果当前结点在第一行就与第一个超级结点合并,
如果当前结点在最后一行就与第二个超级结点合并。

如果第一个超级结点与第二个超级结点时联通的说明当前有第一行与最后一行之间有通路。

class Solution {
public:
    int latestDayToCross(int row, int col, vector<vector<int>>& cells) {
        vector<int> f;
        for(int i=0;i<row*col+2;i++){
            f.push_back(i);
        }
        int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
        int cnt = 0;
        int n = cells.size(),sz = row * col;
        vector<vector<int>> vis(row,vector<int>(col,0));
        for(int i=n-1;i>=0;i--){
            int x = cells[i][0] - 1,y = cells[i][1] - 1;
            int id = x * col + y;
            vis[x][y] = 1;
            for(int i=0;i<4;i++){
                int nx = x + dx[i];
                int ny = y + dy[i];
                if(nx < 0 || nx >= row || ny < 0 || ny >= col || !vis[nx][ny]) continue;
                int nid = nx * col + ny;
                unions(id,nid,f);
            }
            if(x == 0) unions(id,row*col,f);
            if(x == row - 1) unions(id,row*col+1,f);
            if(finds(sz,f) == finds(sz+1,f)){
                cnt++;
                break;
            }else{
                cnt++;
            }
        }
        return n - cnt;
    }

    int finds(int x,vector<int>& f){
        return x == f[x] ? x : f[x] = finds(f[x],f);
    }

    bool unions(int x,int y,vector<int>& f){
        x = finds(x,f);
        y = finds(y,f);
        if(x != y){
            f[x] = y;
            return false;
        }
        return true;
    }
    
};
posted @   Isaac233  阅读(70)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示