2022-01-29每日刷题打卡

2022-01-29每日刷题打卡

1926. 迷宫中离入口最近的出口

给你一个 m x n 的迷宫矩阵 maze (下标从 0 开始),矩阵中有空格子(用 ‘.’ 表示)和墙(用 ‘+’ 表示)。同时给你迷宫的入口 entrance ,用 entrance = [entrancerow, entrancecol] 表示你一开始所在格子的行和列。

每一步操作,你可以往 上,下,左 或者 右 移动一个格子。你不能进入墙所在的格子,你也不能离开迷宫。你的目标是找到离 entrance 最近 的出口。出口 的含义是 maze 边界 上的 空格子。entrance 格子 不算 出口。

请你返回从 entrance 到最近出口的最短路径的 步数 ,如果不存在这样的路径,请你返回 -1 。

示例 1:

nearest1-grid.jpg (333×253) (leetcode.com)

输入:maze = [["+","+",".","+"],[".",".",".","+"],["+","+","+","."]], entrance = [1,2]
输出:1
解释:总共有 3 个出口,分别位于 (1,0),(0,2) 和 (2,3) 。
一开始,你在入口格子 (1,2) 处。

  • 你可以往左移动 2 步到达 (1,0) 。
  • 你可以往上移动 1 步到达 (0,2) 。
    从入口处没法到达 (2,3) 。
    所以,最近的出口是 (0,2) ,距离为 1 步。

以题目给的坐标为起点开始广度搜索,向四周扩散,广度搜索结束后遍历一下最外层的四个边,找出最小值。

class Solution {
public:
    typedef pair<int,int>PII;
    PII que[10010];
    int nearestExit(vector<vector<char>>& maze, vector<int>& entrance) {
        int m=maze[0].size(),n=maze.size();
        int dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
        que[0]={entrance[0],entrance[1]};
        maze[entrance[0]][entrance[1]]='+';
        vector<vector<int>>v(n,vector<int>(m,0));
        int hh=0,tt=0;
        while(hh<=tt)
        {
            auto t=que[hh++];
            for(int i=0;i<4;i++)
            {
                int a=t.first+dx[i],b=t.second+dy[i];
                if(a>=0&&a<n&&b>=0&&b<m&&maze[a][b]=='.'&&v[a][b]==0)
                {
                    v[a][b]=v[t.first][t.second]+1;
                    que[++tt]={a,b};
                }
            }
        }
        int res=INT_MAX;
        for(int i=0;i<n;i++)
        {
            if(v[i][0]!=0)res=min(res,v[i][0]);
            if(v[i][m-1]!=0)res=min(res,v[i][m-1]);
        }
        for(int i=0;i<m;i++)
        {
            if(v[0][i]!=0)res=min(res,v[0][i]);
            if(v[n-1][i]!=0)res=min(res,v[n-1][i]);
        }
        return res==INT_MAX?-1:res;
    }
};
1992. 找到所有的农场组

给你一个下标从 0 开始,大小为 m x n 的二进制矩阵 land ,其中 0 表示一单位的森林土地,1 表示一单位的农场土地。

为了让农场保持有序,农场土地之间以矩形的 农场组 的形式存在。每一个农场组都 仅 包含农场土地。且题目保证不会有两个农场组相邻,也就是说一个农场组中的任何一块土地都 不会 与另一个农场组的任何一块土地在四个方向上相邻。

land 可以用坐标系统表示,其中 land 左上角坐标为 (0, 0) ,右下角坐标为 (m-1, n-1) 。请你找到所有 农场组 最左上角和最右下角的坐标。一个左上角坐标为 (r1, c1) 且右下角坐标为 (r2, c2) 的 农场组 用长度为 4 的数组 [r1, c1, r2, c2] 表示。

请你返回一个二维数组,它包含若干个长度为 4 的子数组,每个子数组表示 land 中的一个 农场组 。如果没有任何农场组,请你返回一个空数组。可以以 任意顺序 返回所有农场组。

示例 1:

screenshot-2021-07-27-at-12-23-15-copy-of-diagram-drawio-diagrams-net.png (788×788) (leetcode.com)

输入:land = [[1,0,0],[0,1,1],[0,1,1]]
输出:[[0,0,0,0],[1,1,2,2]]
解释:
第一个农场组的左上角为 land[0][0] ,右下角为 land[0][0] 。
第二个农场组的左上角为 land[1][1] ,右下角为 land[2][2] 。

广度搜索,遍历矩阵,找到数值为1的地块时,以那块地块为起点开始广度搜索,整体来说就和岛屿问题差不多,只不过这里返回的不是岛屿的数量,而是岛屿的左上角坐标和右下角坐标,说人话就是,左上角坐标就是x坐标和y坐标是岛屿中最小的,右下角就是最大的。而因为这里的农村都是矩阵,所以我们遍历到的第一个坐标自然就是最小的坐标,即左上角坐标。然后在广度搜索中,找出坐标最大的那个点,即右下角坐标。

class Solution {
public:
    typedef pair<int,int>PII;
    PII que[100000];
    int dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
    int n,m;
    vector<vector<int>> findFarmland(vector<vector<int>>& land) {
        vector<vector<int>>v;
        n=land.size(),m=land[0].size();
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                if(land[i][j]==1)
                {
                    vector<int>ans;
                    ans.push_back(i);
                    ans.push_back(j);
                    bfs(land,i,j,ans);
                    v.push_back(ans);
                }
            }
        }
        return v;
    }
    void bfs(vector<vector<int>>& land,int x,int y,vector<int>&v)
    {
        que[0]={x,y};
        land[x][y]=0;
        int hh=0,tt=0;
        int max_x=x,max_y=y;
        while(hh<=tt)
        {
            auto t=que[hh++];
            for(int i=0;i<4;i++)
            {
                int a=t.first+dx[i],b=t.second+dy[i];
                if(a>=0&&a<n&&b>=0&&b<m&&land[a][b]==1)
                {
                    que[++tt]={a,b};
                    land[a][b]=0;
                    max_x=max(max_x,a);
                    max_y=max(max_y,b);
                }
            }
        }
        v.push_back(max_x);
        v.push_back(max_y);
    }
};
2059. 转化数字的最小运算数

给你一个下标从 0 开始的整数数组 nums ,该数组由 互不相同 的数字组成。另给你两个整数 start 和 goal 。

整数 x 的值最开始设为 start ,你打算执行一些运算使 x 转化为 goal 。你可以对数字 x 重复执行下述运算:

如果 0 <= x <= 1000 ,那么,对于数组中的任一下标 i(0 <= i < nums.length),可以将 x 设为下述任一值:

x + nums[i]
x - nums[i]
x ^ nums[i](按位异或 XOR)
注意,你可以按任意顺序使用每个 nums[i] 任意次。使 x 越过 0 <= x <= 1000 范围的运算同样可以生效,但该该运算执行后将不能执行其他运算。

返回将 x = start 转化为 goal 的最小操作数;如果无法完成转化,则返回 -1 。

示例 1:

输入:nums = [1,3], start = 6, goal = 4
输出:2
解释:
可以按 6 → 7 → 4 的转化路径进行,只需执行下述 2 次运算:

  • 6 ^ 1 = 7
  • 7 ^ 3 = 4

迷宫问题,区别就是迷宫是在矩阵中上下左右四个方向移动,这里是对数start进行+,-,^,三个操作使其变成goal,准备一个计数器ans=0,每进行一次操作后++。注意的是,这里的数是有界限的,超过0~1000的区间后就没必要记录了,因为记录了也不能进行下一次运算,直接判断是否等于目标值goal即可,如果等于就返回ans+1。顺便还要记录一下每个数的出现情况,如果出现过了就不做处理(出现过了说明也对它做过运算了)。

class Solution {
public:
    int minimumOperations(vector<int>& nums, int start, int goal) {
        queue<int>que;
        vector<int>v(1001);
        v[start]++;
        que.push(start);
        int ans=0,n=nums.size();
        while(que.size())
        {
            int len=que.size();
            
            for(int i=0;i<len;i++)
            {
                int t=que.front();
                que.pop();
                if(t==goal)return ans;
                if(t>1000||t<0)continue;
                for(int j=0;j<n;j++)
                {
                    int o=t+nums[j],p=t-nums[j],q=t^nums[j];
                    if(o>1000||o<0)
                    {
                        if(o==goal)return ans+1;
                    }
                    else if(v[o]==0)
                    {
                        v[o]=1;
                        que.push(o);
                    }
                    if(p>1000||p<0)
                    {
                        if(p==goal)return ans+1;
                    }
                    else if(v[p]==0)
                    {
                        v[p]=1;
                        que.push(p);
                    }
                    if(q>1000||q<0)
                    {
                        if(q==goal)return ans+1;
                    }
                    else if(v[q]==0)
                    {
                        v[q]=1;
                        que.push(q);
                    }
                }
            }
            ans++;
        }
        return -1;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值