A题:1137. 第 N 个泰波那契数
人尽皆知傻逼题,直接数组模拟。
B题:1138. 字母板上的路径
我们从一块字母板上的位置 (0, 0) 出发,该坐标对应的字符为 board[0][0]。
在本题里,字母板为board = [“abcde”, “fghij”, “klmno”, “pqrst”, “uvwxy”, “z”].
我们可以按下面的指令规则行动:
如果方格存在,‘U’ 意味着将我们的位置上移一行;
如果方格存在,‘D’ 意味着将我们的位置下移一行;
如果方格存在,‘L’ 意味着将我们的位置左移一列;
如果方格存在,‘R’ 意味着将我们的位置右移一列;
‘!’ 会把在我们当前位置 (r, c) 的字符 board[r][c] 添加到答案中。
返回指令序列,用最小的行动次数让答案和目标 target 相同。你可以返回任何达成目标的路径。
思路:一道模拟题,比较有意思了。做法就是按照题意模拟,我采用的做法是,实现一个字符移动到另一个字符的串的函数,再依次扫描target串就可以了。
代码如下:
class Solution {
public:
string string_copy(string str,int time){
string res = "";
for(int i=0;i<time;++i)
res += str;
return res;
}
string oneToone(int src,int des){
string res = "";
int sr = src/5,dr = des/5;
if(sr == dr){
//src和des在同一行
if(src < des) return string_copy("R",des-src);
else return string_copy("L",src-des);
}
else{
if(sr != 5 && dr != 5){
int dis = abs(sr-dr);
if(sr < dr){
res += string_copy("D",dis);
res += oneToone(src+dis*5,des);
}
else{
res += string_copy("U",dis);
res += oneToone(src-dis*5,des);
}
}
else{
if(sr == 5){
//即src是z
res += 'U';//src先移动到z上面的位置
res += oneToone(src-5,des);
}
else{
//des是z
// res += string_copy("D",dr-sr-1);
// res += string_copy("L",src%5);
res += oneToone(src,20);//先到达z上面的位置
res += "D";
}
}
}
return res;
}
string alphabetBoardPath(string target) {
// return oneToone(0,11);
string res = "";
int last = 0;
for(int i=0;i<target.size();++i){
int now = target[i]-'a';
// printf("last = %d,now = %d\n",last,now);
string temp = oneToone(last,now);
if(temp.size() != 0)
res += temp;
res += '!';
last = now;
}
return res;
}
};
C题:1139. 最大的以 1 为边界的正方形
给你一个由若干 0 和 1 组成的二维网格 grid,请你找出边界全部由 1 组成的最大 正方形 子网格,并返回该子网格中的元素数量。如果不存在,则返回 0。
示例 1:
输入:grid = [[1,1,1],[1,0,1],[1,1,1]]
输出:9
示例 2:
输入:grid = [[1,1,0,0]]
输出:1
1 <= grid.length <= 100
1 <= grid[0].length <= 100
grid[i][j] 为 0 或 1
思路:因为范围比较小,所以我就直接暴力了,求出每一个为1的点 上下左右 能到达1的长度。然后扫描左右的点,考虑当前点作为正方形的左上角坐标时,最大面积时多少。从当前点想右下一直扫描。最大扫描长度是min(right,down).注意遇到0也是要继续扫描。
如图是扫描路线。
代码如下:
class Solution {
public:
vector<vector<int>> vec;
int up[110][110];
int left[110][110];
int right[110][110];
int down[110][110];
int N,M;
void init(){
memset(up,0,sizeof(up));
memset(left,0,sizeof(left));
memset(right,0,sizeof(right));
memset(down,0,sizeof(down));
N = vec.size();
M = vec[0].size();
for(int i=0;i<N;++i){
for(int j=0;j<M;++j){
if(vec[i][j] == 0){
up[i][j] = left[i][j] = right[i][j] = down[i][j] = 0;
}
else{
int Count = 0;
int k = i;
while(--k >= 0 && vec[k][j] == 1)
Count++;
up[i][j] = Count;
Count = 0;
k = j;
while(--k >= 0 && vec[i][k] == 1)
Count++;
left[i][j] = Count;
Count = 0;
k = j;
while(++k < M && vec[i][k] == 1)
Count++;
right[i][j] = Count;
Count = 0;
k = i;
while(++k < N && vec[k][j] == 1)
Count++;
down[i][j] = Count;
}
}
}
}
void show(){
for(int i=0;i<N;++i){
for(int j=0;j<M;++j){
printf("%d %d %d %d %d %d\n",i,j,up[i][j],left[i][j],right[i][j],down[i][j]);
}
}
}
int largest1BorderedSquare(vector<vector<int>>& grid) {
vec = grid;
init();
int MaxSize = 0;
for(int i=0;i<N;++i){
for(int j=0;j<M;++j){
if(grid[i][j] == 1){
int now = 0;
int Max = min(right[i][j],down[i][j]);
while(now <= Max){
if(grid[i+now][j+now] == 1 && left[i+now][j+now] >= now && up[i+now][j+now] >= now){
MaxSize = max(MaxSize,(now+1)*(now+1));
}
now++;
}
}
}
}
//show();
return MaxSize;
}
};
我写的可能有点傻逼,应该是有更简单的做法的。
D题:1140. 石子游戏 II
亚历克斯和李继续他们的石子游戏。许多堆石子 排成一行,每堆都有正整数颗石子 piles[i]。游戏以谁手中的石子最多来决出胜负。
亚历克斯和李轮流进行,亚历克斯先开始。最初,M = 1。
在每个玩家的回合中,该玩家可以拿走剩下的 前 X 堆的所有石子,其中 1 <= X <= 2M。然后,令 M = max(M, X)。
游戏一直持续到所有石子都被拿走。
假设亚历克斯和李都发挥出最佳水平,返回亚历克斯可以得到的最大数量的石头。
示例:
输入:piles = [2,7,9,4,4]
输出:10
解释:
如果亚历克斯在开始时拿走一堆石子,李拿走两堆,接着亚历克斯也拿走两堆。在这种情况下,亚历克斯可以拿到 2 + 4 + 4 = 10 颗石子。
如果亚历克斯在开始时拿走两堆石子,那么李就可以拿走剩下全部三堆石子。在这种情况下,亚历克斯可以拿到 2 + 7 = 9 颗石子。
所以我们返回更大的 10。
提示:
1 <= piles.length <= 100
1 <= piles[i] <= 10 ^ 4
思路:动态规划的做法。从后往前考虑。
dp[i][j] 表示i - n堆石子时,M = j 当前最大能拿走的石子.
即倒着推,当前考虑的是,如果当前k堆,获得的收益和即为sum[i] - dp[i+k][max(j,k)
∑ k = 1 2 ∗ j d p [ i ] [ j ] = m a x ( d p [ i ] [ j ] , s u m [ i ] − d p [ i + k ] [ m a x ( j , k ) ] \sum_{k=1}^{2*j}dp[i][j] = max(dp[i][j],sum[i]-dp[i+k][max(j,k)] k=1∑2∗jdp[i][j]=max(dp[i][j],sum[i]−dp[i+k][max(j,k)]
代码如下:
class Solution {
public:
int dp[110][110];
int sum[110];
int stoneGameII(vector<int>& piles) {
int N = piles.size();
memset(dp,0,sizeof(dp));
memset(sum,0,sizeof(sum));
for(int i=N-1;i>=0;--i)
sum[i] = sum[i+1] + piles[i];
for(int i=N-1;i>=0;--i){
for(int j=1;j<=N;++j){
for(int k=1;k<=2*j && i+k <= N;++k){
dp[i][j] = max(dp[i][j],sum[i]-dp[i+k][max(j,k)]);
}
}
}
return dp[0][1];
}
};