【Leetcode】第134场周赛

5039. 移动石子直到连续

三枚石子放置在数轴上,位置分别为 a a a b b b c c c

每一回合,我们假设这三枚石子当前分别位于位置 x , y , z x, y, z x,y,z x < y < z x < y < z x<y<z。从位置 x x x 或者是位置 z z z 拿起一枚石子,并将该石子移动到某一整数位置 k k k 处,其中 x < k < z x < k < z x<k<z k ! = y k != y k!=y

当你无法进行任何移动时,即,这些石子的位置连续时,游戏结束。

要使游戏结束,你可以执行的最小和最大移动次数分别是多少? 以长度为 2 2 2 的数组形式返回答案: a n s w e r = [ m i n i m u m answer = [minimum answer=[minimum_ m o v e s moves moves, m a x i m u m maximum maximum_ m o v e s ] moves] moves]

示例 1:

输入:a = 1, b = 2, c = 5
输出:[1, 2]
解释:将石子从 5 移动到 4 再移动到 3,或者我们可以直接将石子移动到 3

示例 2:

输入:a = 4, b = 3, c = 2
输出:[0, 0]
解释:我们无法进行任何移动。

提示:

1. 1 <= a <= 100
2. 1 <= b <= 100
3. 1 <= c <= 100
4. a != b, b != c, c != a

思路:将三个位置按从小到大排序。判断 b − a b-a ba大小与 c − b c-b cb大小,如果 b − a = 1 b-a=1 ba=1并且 c − b = 1 c-b=1 cb=1,那么说明这三个石子已经相邻,不需要移动, m i n min min_ m o v e move move m a x max max_ m o v e move move都为 0 0 0;如果两者有一个 = 1 =1 =1,另一个不为 1 1 1,则最小移动次数即为 1 1 1,最大移动次数即为 b − a − 1 b-a-1 ba1 c − b − 1 c-b-1 cb1;如果 b − a = 2 b-a=2 ba=2 c − b c-b cb 2 2 2,那么最小移动次数即为将另外一个石子移动到中间即可,否则则需移动两次,最大移动次数即为 b − a − 1 + c − b − 1 b-a-1+c-b-1 ba1+cb1

class Solution {
public:
    vector<int> ans;
    vector<int> numMovesStones(int a, int b, int c) {
    	//排序
        if (a > b)
            swap(a, b);
        if (a > c)
            swap(a, c);
        if (b > c)
            swap(b, c);
        int min_move, max_move;
        //相邻
        if (b - a == 1 && c - b == 1) {
            min_move = 0;
            max_move = 0;
        }
        //有两个相邻而另一个不相邻
        else if (b - a == 1 || c - b == 1) {
            min_move = 1;
            max_move = max(b - a - 1, c - b - 1);
        }
        else {
        	//如果出现相距为2的情况,则最少只需移动一次
            if (b - a == 2 || c - b == 2)
                min_move = 1;
            else
                min_move = 2;
            max_move = b - a - 1 + c - b - 1;
        }
        ans.push_back(min_move);
        ans.push_back(max_move);
        return ans;
    }
};

5040. 边框着色

给出一个二维整数网格 g r i d grid grid,网格中的每个值表示该位置处的网格块的颜色。

只有当两个网格块的颜色相同,而且在四个方向中任意一个方向上相邻时,它们属于同一连通分量。

连通分量的边界是指连通分量中的所有与不在分量中的正方形相邻(四个方向上)的所有正方形,或者在网格的边界上(第一行/列或最后一行/列)的所有正方形。

给出位于 ( r 0 , c 0 ) (r0, c0) (r0,c0) 的网格块和颜色 c o l o r color color,使用指定颜色 c o l o r color color 为所给网格块的连通分量的边界进行着色,并返回最终的网格 g r i d grid grid

示例 1:

输入:grid = [[1,1],[1,2]], r0 = 0, c0 = 0, color = 3
输出:[[3, 3], [3, 2]]

示例 2:

输入:grid = [[1,2,2],[2,3,2]], r0 = 0, c0 = 1, color = 3
输出:[[1, 3, 3], [2, 3, 3]]

示例 3:

输入:grid = [[1,1,1],[1,1,1],[1,1,1]], r0 = 1, c0 = 1, color = 2
输出:[[2, 2, 2], [2, 1, 2], [2, 2, 2]]

提示:

1. 1 <= grid.length <= 50
2. 1 <= grid[0].length <= 50
3. 1 <= grid[i][j] <= 1000
4. 0 <= r0 < grid.length
5. 0 <= c0 < grid[0].length
6. 1 <= color <= 1000

思路:本题难点在于对于题目意思的理解,只要理解了题目中所说的边界就很好做了;根据题意及示例可以得出需要着色的边框分为 2 2 2类,第一类即处于第一行/列或最后一行/列的正方形,第二类即处于边界,这里指的是对于一个网格,其周围四个方向连通分量与其颜色一致,那么不需要着色,只要出现不一致则需要将该网格着色

class Solution {
public:
    int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
    using pii = pair<int, int>;
    vector<vector<int>> colorBorder(vector<vector<int>>& grid, int r0, int c0, int color) {
        int n = grid.size();
        int m = grid[0].size();
        vector<vector<int>> ret = grid, u(n, vector<int>(m));
        queue<pii> q;
        q.push(pii(r0, c0));
        u[r0][c0] = 1;
        while (!q.empty()) {
            int x = q.front().first;
            int y = q.front().second;
            q.pop();
            bool flag = 0;
            //与该网格处于同一连通分量,判断是否一致
            for (int i = 0;i < 4; ++i) {
                int tx = x + dir[i][0];
                int ty = y + dir[i][1];
                //一致则标记该网格
                if (tx >= 0 && tx < n && ty >= 0 && ty < m && !u[tx][ty] && grid[tx][ty] == grid[r0][c0]) {
                    u[tx][ty] = 1;
                    q.push(pii(tx, ty));
                }
                //出现一个不满足条件的网格
                if (!(tx >= 0 && tx < n && ty >= 0 && ty < m  && grid[tx][ty] == grid[r0][c0]))
                    flag = 1;
            }
            //将当前判断网格着色
            if (flag) ret[x][y] = color;
        }
        return ret;
    }
};

5041. 不相交的线

我们在两条独立的水平线上按给定的顺序写下 A A A B B B 中的整数。

现在,我们可以绘制一些连接两个数字 A [ i ] A[i] A[i] B [ j ] B[j] B[j] 的直线,只要 A [ i ] = = B [ j ] A[i] == B[j] A[i]==B[j],且我们绘制的直线不与任何其他连线(非水平线)相交。

以这种方法绘制线条,并返回我们可以绘制的最大连线数。

示例 1:

输入:A = [1,4,2], B = [1,2,4]
输出:2
解释:
我们可以画出两条不交叉的线,如上图所示。
我们无法画出第三条不相交的直线,因为从 A[1]=4 到 B[2]=4 的直线将与从 A[2]=2 到 B[1]=2 的直线相交。

示例 2:

输入:A = [2,5,1,2,5], B = [10,5,2,1,5,2]
输出:3

示例 3:

输入:A = [1,3,7,1,7,5], B = [1,9,2,5,1]
输出:2

提示:

1. 1 <= A.length <= 500
2. 1 <= B.length <= 500
3. 1 <= A[i], B[i] <= 2000

思路:动态规划( d p dp dp)。

  • d p [ i ] [ j ] dp[i][j] dp[i][j]表示 A A A中前 i i i个数与 B B B中前 j j j个数构成的最大连线数。考虑以下两种情况
  • 1)当 A [ i ] = = B [ j ] A[i] == B[j] A[i]==B[j]时,此时最大连接数由 d p [ i − 1 ] [ j − 1 ] dp[i - 1][j - 1] dp[i1][j1]决定,即 d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] + 1 dp[i][j] = dp[i - 1][j - 1] + 1 dp[i][j]=dp[i1][j1]+1
  • 2) A [ i ] ! = B [ j ] A[i] != B[j] A[i]!=B[j],那么最大连接数即有两种情况,可能为 d p [ i − 1 ] [ j ] dp[i - 1][j] dp[i1][j],也可能为 d p [ i ] [ j − 1 ] dp[i][j - 1] dp[i][j1],去两者最大值, d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i ] [ j − 1 ] ) dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) dp[i][j]=max(dp[i1][j],dp[i][j1])
class Solution {
public:
    int a[505], b[505];
    int maxUncrossedLines(vector<int>& A, vector<int>& B) {
        int n = A.size();
        int m = B.size();
        for (int i = 0; i < n; ++i)
            a[i + 1] = A[i];
        for (int j = 0; j < m; ++j) 
            b[j + 1] = B[j];
        int dp[n + 1][m + 1];
        memset(dp, 0, sizeof(dp));
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= m; ++j) {
                if (a[i] == b[j])
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                else
                    dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
            }
        }
        return dp[n][m];
    }
};

5042. 逃离大迷宫

在一个 1 0 6 ∗ 1 0 6 10^6 * 10^6 106106 的网格中,每个网格块的坐标为 ( x , y ) (x, y) (x,y),其中 0 < = x , y < 1 0 6 0 <= x, y < 10^6 0<=x,y<106

我们从源方格 s o u r c e source source 开始出发,意图赶往目标方格 t a r g e t target target。每次移动,我们都可以走到网格中在四个方向上相邻的方格,只要该方格不在给出的封锁列表 b l o c k e d blocked blocked 上。

只有在可以通过一系列的移动到达目标方格时才返回 t r u e true true。否则,返回 f a l s e false false

示例 1:

输入:blocked = [[0,1],[1,0]], source = [0,0], target = [0,2]
输出:false
解释:
从源方格无法到达目标方格,因为我们无法在网格中移动。

示例 2:

输入:blocked = [], source = [0,0], target = [999999,999999]
输出:true
解释:
因为没有方格被封锁,所以一定可以到达目标方格。

提示:

1. 0 <= blocked.length <= 200
2. blocked[i].length == 2
3. 0 <= blocked[i][j] < 10^6
4. source.length == target.length == 2
5. 0 <= source[i][j], target[i][j] < 10^6
6. source != target

思路:首先,常规的 d f s dfs dfs肯定超时。然后观察提示,注意到封锁列表最多只有 200 200 200个点,那么我们封锁区域形成的三角形所能包围的最多的点数: 200 ∗ 200 / 2 − 200 / 2 = 19900 200*200/2 - 200/2 = 19900 200200/2200/2=19900个,那么我们只需计算从起点出发能走的步数是否超过 19900 19900 19900,同时从终点出发能走的步数是否超过 19900 19900 19900,如果同时超过则说明起点与终点没有被封锁,则一定有解

class Solution {
public:
    int dir[4][2] = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}};
    //三角形所能围住的点:200*200/2 - 200/2 = 19900个
    //只要从起点出发走出19900步+从终点出发走出19900步说明起点与终点都没有被围住,则有解
    const int limit = 20000;
    using pii = pair<int, int>;
    using ll = long long;
    bool isEscapePossible(vector<vector<int>>& blocked, vector<int>& source, vector<int>& target) {
        unordered_set<ll> a;
        for (auto p : blocked) 
            a.insert(p[0] * 1000000LL + p[1]);
        auto check = [&](vector<int> s, vector<int> t) {
            unordered_set<ll> u;
            u.insert(s[0] * 1000000LL + s[1]);
            int tot = 0;
            queue<pii> q;
            q.push(pii(s[0], s[1]));
            while(!q.empty()) {
                int x = q.front().first;
                int y = q.front().second;
                q.pop();
                ++tot;
                if (tot >= limit) return true;
                if (x == t[0] && y == t[1])  return true;
                for (int i = 0; i < 4; ++i) {
                    int tx = x + dir[i][0];
                    int ty = y + dir[i][1];
                    if (tx >= 0 && tx < 1000000 && ty >= 0 && ty < 1000000 
                        && !a.count(tx * 1000000LL + ty) && !u.count(tx * 1000000LL + ty)) {
                        u.insert(tx * 1000000LL + ty);
                        q.push(pii(tx, ty));
                    }
                }
            }
            return false;
        };
        return check(source, target) && check(target, source);
    }
};

你可能感兴趣的:(【Leetcode】)