leetcoe 第 147 场周赛 题解

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=12jdp[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];
    }
};
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页