三枚石子放置在数轴上,位置分别为 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 b−a大小与 c − b c-b c−b大小,如果 b − a = 1 b-a=1 b−a=1并且 c − b = 1 c-b=1 c−b=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 b−a−1或 c − b − 1 c-b-1 c−b−1;如果 b − a = 2 b-a=2 b−a=2或 c − b c-b c−b为 2 2 2,那么最小移动次数即为将另外一个石子移动到中间即可,否则则需移动两次,最大移动次数即为 b − a − 1 + c − b − 1 b-a-1+c-b-1 b−a−1+c−b−1
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;
}
};
给出一个二维整数网格 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;
}
};
我们在两条独立的水平线上按给定的顺序写下 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)。
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];
}
};
在一个 1 0 6 ∗ 1 0 6 10^6 * 10^6 106∗106 的网格中,每个网格块的坐标为 ( 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 200∗200/2−200/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);
}
};