Leetcode Weekly Contest 147

2019-08-20  本文已影响0人  crishawy

1. 题目列表

2. 第 N 个泰波那契数

题目描述:

泰波那契序列 Tn 定义如下:

T0 = 0, T1 = 1, T2 = 1, 且在 n >= 0 的条件下 Tn+3 = Tn + Tn+1 + Tn+2

给你整数 n,请返回第 n 个泰波那契数 Tn 的值。

代码:

class Solution {
public:
    int tribonacci(int n) {
        int a = 0, b = 1, c = 1, d;
        if (n == 0) return 0;
        if (n == 1 || n == 2) return 1;
        while (n - 3 >= 0){
            d = a + b + c;
            a = b;
            b = c;
            c = d;
            n--;
        }
        return d;
    }
};

3. 字母板上的路径

题目描述:

我们从一块字母板上的位置 (0, 0) 出发,该坐标对应的字符为 board[0][0]。

在本题里,字母板为board = ["abcde", "fghij", "klmno", "pqrst", "uvwxy", "z"].

我们可以按下面的指令规则行动:

如果方格存在,'U' 意味着将我们的位置上移一行;
如果方格存在,'D' 意味着将我们的位置下移一行;
如果方格存在,'L' 意味着将我们的位置左移一列;
如果方格存在,'R' 意味着将我们的位置右移一列;
'!' 会把在我们当前位置 (r, c) 的字符 board[r][c] 添加到答案中。
返回指令序列,用最小的行动次数让答案和目标 target 相同。你可以返回任何达成目标的路径。
示例 1:

输入:target = "leet"
输出:"DDR!UURRR!!DDD!"
示例 2:

输入:target = "code"
输出:"RR!DDRR!UUL!R!"

提示:

1 <= target.length <= 100
target 仅含有小写英文字母。

解决思路:

正解:根据字母的字典大小判断在二维字典中的相对位置行走,注意到'z'时,需要回头。此处,我使用的是BFS+路径记录(复习)。

代码:

class Solution {
public:
    struct Node{
        int x, y, id, pre;
        char op;
    }nodes[50]; // 创建node数组,为了记录BFS路径 
    int X[4] = {-1, 1, 0, 0};
    int Y[4] = {0, 0, -1, 1};
    char cs[7][6] = {{'a', 'b', 'c', 'd', 'e'},{'f', 'g', 'h', 'i', 'j'},
    {'k', 'l', 'm', 'n', 'o'}, {'p', 'q', 'r', 's', 't'}, {'u', 'v', 'w', 'x', 'y'}, {'z'}};
    bool visited[7][6];
    string res;
    
    Node create(int x, int y, int id, int pre, char op){
        nodes[id].id = id, nodes[id].x = x, nodes[id].y = y, nodes[id].pre = pre, nodes[id].op = op;
        return nodes[id];
    }
    
    int BFS(int sx, int sy, char dest){
        queue<Node> q;
        while (!q.empty()) q.pop();
        memset(visited, false, sizeof(visited));
        memset(nodes, NULL, sizeof(nodes));
        int index = 0;
        q.push(create(sx, sy, index++, -1, ' '));
        visited[sx][sy] = true;
        while (!q.empty()){
            Node node = q.front();
            q.pop();
//          printf("当前访问c(%d, %d)=%c,节点ID=%d\n",node.x, node.y, cs[node.x][node.y], node.id);
            if (cs[node.x][node.y] == dest){
//              nodes[node.id].op = '!';
                return node.id;         
            }
            for (int i = 0; i < 4; i++){
                int newX = node.x + X[i];
                int newY = node.y + Y[i];
                if (newX < 0 || newX > 5 || newY < 0 || newY > 4 || visited[newX][newY] || (newX == 5 && newY > 0))
                    continue;
                if (i == 0){
                    q.push(create(newX, newY, index++, node.id, 'U'));
                }else if (i == 1){
                    q.push(create(newX, newY, index++, node.id, 'D'));
                }else if (i == 2){
                    q.push(create(newX, newY, index++, node.id, 'L'));
                }else{
                    q.push(create(newX, newY, index++, node.id, 'R'));
                }
                visited[newX][newY] = true;
            }
        }
        return -1;
    }
    
    void printPath(int id){
        if (id == -1) return;
        printPath(nodes[id].pre); // 深度优先访问前驱节点 
        if (nodes[id].pre != -1)
            res = res + nodes[id].op;
    }
    
    string alphabetBoardPath(string target) {
        int x = 0, y = 0;
        for (int i = 0; i < target.length(); i++){
            int targetId = BFS(x, y, target[i]);
//          printf("targetId= %d\n", targetId);
            printPath(targetId);
            res = res + '!';
//          printf("suc2\n");
            x = nodes[targetId].x;
            y = nodes[targetId].y;
        }
        return res;
    }
};

4. 最大的以 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

解决思路:

穷举正方形边长判断即可。

代码:

class Solution {
public:
    int largest1BorderedSquare(vector< vector<int> >& grid) {
        int m = grid.size(), n = grid[0].size();
        int MAX = 0;
        for (int l = 1; l <= min(m, n); l++){
            for (int i = 0; i < m - l + 1; i++){
                for (int j = 0; j < n - l + 1; j++){
                    bool flag = true;
                    for (int k = i; k < i + l; k++){
                        if (grid[k][j] == 0){
                            flag = false;
                            break;
                        }
                        if (grid[k][j + l - 1] == 0){
                            flag = false;
                            break;
                        }
                    }
                    if (flag){
                        for (int k = j; k < j + l; k++){
                            if (grid[i][k] == 0){
                                flag = false;
                                break;
                            }
                            if (grid[i + l - 1][k] == 0){
                                flag = false;
                                break;
                            }
                        }
                    }
                    if (flag){
                        if (l * l > MAX) MAX = l * l;
                    }
                }
            }
        }
        return MAX; 
    }
};

4. 石子游戏 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数组为当前玩家最优的拿石头策略。
    因此,定义dp[i][j]表示从第i堆石头拿到第n堆石头、M=j时的最大拿石数量,
    则当我从第i到第n堆石头堆里拿取k堆石头后,那么对手将在第i+k到n堆石头堆
    里拿到最大的数量且j = max(j, k),所以穷举k= 1, 2, ..., 2j,找出dp[i][j]的最大值。
    状态转移方程为:
        dp[i][j] = max(dp[i][j], sum[i~n] - dp[i + k][max(k, j)]), k = 1, 2, ..., 2j
    逆序穷举i和j即可

代码:

class Solution {
public:
    int sum(vector<int>& piles, int l, int r){
        int s = 0;
        for (int i = l; i <= r; i++)
            s += piles[i];
        return s;
    }
    int stoneGameII(vector<int>& piles) {
        int dp[300][300];
        memset(dp, 0, sizeof(dp));
        int n = piles.size();
        for (int i = n - 1; i >= 0; i--){
            for (int j = n; j >= 1; j--){
                for (int k = 1; k <= 2 * j; k++)
                    dp[i][j] = max(dp[i][j], sum(piles, i, n - 1) - dp[i + k][max(k, j)]);
            }
        }
        return dp[0][1];
    }
};
上一篇下一篇

猜你喜欢

热点阅读