leetcode第147场周赛

有点忧伤,博弈题没做出来,前面还wa了好几次。

第一题 第 N 个泰波那契数

题目大意

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

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

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

解题思路

        类似于斐波那契数列,只不过将两个数的和变成了三个数的和。

代码如下

class Solution:
    def tribonacci(self, n: int) -> int:
        t_list = [0,1,1]
        length = len(t_list)
        while length <= n + 1:
            t_list.append(t_list[length - 1] + t_list[length - 2] + t_list[length - 3])
            length += 1
        return t_list[n]

第二题 字母板上的路径

题目大意

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

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

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

            如果方格存在,'U' 意味着将我们的位置上移一行;

            如果方格存在,'D' 意味着将我们的位置下移一行;

            如果方格存在,'L' 意味着将我们的位置左移一列;

            如果方格存在,'R' 意味着将我们的位置右移一列;

    '!' 会把在我们当前位置 (r, c) 的字符 board[r][c] 添加到答案中。

        返回指令序列,用最小的行动次数让答案和目标 target 相同。你可以返回任何达成目标的路径。

解题思路

        题目的关键点:如果方格存在,又没注意,wa了一次。

        这是一个6*5的不完整矩阵,最后一行只有一个'z'。如果不考虑最后一个'z',那么路径即为x_new - x_old 再 y_new - y_old 地跑。那么再考虑一下'z'这种特殊情况,如果上一个字母为'z',我们要跑去下一个非'z'字母,那一定是先向上跑,因为右边已经过不去了;另一种情况,我们要从其它字母跑去'z',那么我们可以先跑到第一列,然后再向下跑。

代码如下

class Solution:
    def alphabetBoardPath(self, target: str) -> str:
        x, y = 0, 0
        ans = ''
        for each in target:
            ascii_num = ord(each)
            new_x = (ascii_num - 97) // 5
            new_y = (ascii_num - 97) % 5
            if x == 5:
                #如果上一个是'z',就先上下方向跑,然后再左右方向跑
                if new_x - x < 0:
                    for i in range(x - new_x):
                        ans += 'U'
                elif new_x - x > 0:
                    for i in range(new_x - x):
                        ans += 'D'
    
                if new_y - y < 0:
                    for i in range(y - new_y):
                        ans += 'L'
                elif new_y - y > 0:
                    for i in range(new_y - y):
                        ans += 'R'
            else:
                #其它情况(为了照顾目的地为'z'),可以先左右跑,再上下跑
                if new_y - y < 0:
                    for i in range(y - new_y):
                        ans += 'L'
                elif new_y - y > 0:
                    for i in range(new_y - y):
                        ans += 'R'
                        
                if new_x - x < 0:
                    for i in range(x - new_x):
                        ans += 'U'
                elif new_x - x > 0:
                    for i in range(new_x - x):
                        ans += 'D'
                
            ans += '!'
            x = new_x
            y = new_y
        return ans

第三题 最大的以 1 为边界的正方形

题目大意

       给你一个由若干 0 和 1 组成的二维网格 grid,请你找出边界全部由 1 组成的最大 正方形 子网格,并返回该子网格中的元素数量。如果不存在,则返回 0

解题思路

        没考虑到一些细节性问题,又wa了好几次。。。比如边长为1的情况

        边界全为1,如果边长为1,那么边界和为1;如果边长为n(n > 1),那么边界和为 n*4 - 4(每个顶点都算了2次);考虑到这一步,题目就转化成了如何求边界和的值。边界和的值 = 正方形的总值 - 内部正方形的值,然后问题就解决了,具体看代码实现。

代码如下

class Solution:
    def largest1BorderedSquare(self, grid: List[List[int]]) -> int:
        n = len(grid)
        m = len(grid[0])
        #计算长方形([0,0],[i,j])的值,0行0列空出来,方便计算
        sum_grid = [[0 for j in range(m + 1)] for i in range(n + 1)]
        for i in range(n):
            for j in range(m):
                sum_grid[i + 1][j + 1] = sum_grid[i][j + 1] + sum_grid[i + 1][j] - sum_grid[i][j] + grid[i][j]

        for k in range(min(n, m) + 1, 0, -1):
            for i in range(n):
                for j in range(m):
                    i2 = i + k - 1
                    j2 = j + k - 1
                    if i2 < n and j2 < m:
                        #总正方形的值
                        totalsum = sum_grid[i2 + 1][j2 + 1] - sum_grid[i][j2 + 1] - sum_grid[i2 + 1][j] + sum_grid[i][j]

                        #如果边长大于2,减去内部正方形的值
                        if k > 2:
                            in_x1, in_y1 = i + 1, j + 1
                            in_x2, in_y2 = i2 - 1, j2 - 1
                            totalsum -= sum_grid[in_x2 + 1][in_y2 + 1] - sum_grid[in_x1][in_y2 + 1] - sum_grid[in_x2 + 1][in_y1] + sum_grid[in_x1][in_y1]
                        
                        #判断边界和是否为全一,注意边长为一的特例
                        if k > 1:
                            if totalsum == k * 4 - 4:
                                return k*k
                        else:
                            if totalsum == 1:
                                return k
        return 0

第四题 石子游戏 II

题目大意

       许多堆石子 排成一行,每堆都有正整数颗石子 piles[i],亚历克斯和李轮流拿石头,亚历克斯先开始。最初,M = 1

       在每个玩家的回合中,该玩家可以拿走剩下的  X 堆的所有石子,其中 1 <= X <= 2M。然后,令 M = max(M, X)

       游戏一直持续到所有石子都被拿走。

       假设亚历克斯和李都发挥出最佳水平,返回亚历克斯可以得到的最大数量的石头。

解题思路

        博弈题,设f[ i ][ j ]为从第 i 块石头拿到第 n 块石头,M为 j 时的最大值。

       状态转移:当M为j时,我可以拿 1 ~ 2j 块石头,当我拿取k块石头后,又到了对方的回合,这时候他要从i+k至n块石头中找最优策略,故状态转移方程为f[ i ][ j ] = max(f[ i ][ j ],sum[i 至 n] - f[i + k][max(j , k)])   (1<=k<= 2*j) 

       最后的结果即为f[1][1](从第一块石头开始拿,且M为1)

代码如下

class Solution:
    def stoneGameII(self, piles: List[int]) -> int:
        n = len(piles)
        sum_piles = [0]
        for i in range(n):
            sum_piles.append(sum_piles[len(sum_piles) - 1] + piles[i])
        f = [[0 for j in range(n + 1)] for i in range(n + 2)]
        for i in range(n, 0, -1):
            for j in range(1, n + 1):
                for k in range(1, min(2 * j + 1, n + 1)):
                    next_step = min(i + k, n + 1)
                    f[i][j] = max(f[i][j], sum_piles[n] - sum_piles[i - 1] - f[next_step][max(k, j)])

        return f[1][1]

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值