LeetCode 第 147 场周赛 【第 N 个泰波那契数】 【字母板上的路径】 【最大的以 1 为边界的正方形】

1137. 第 N 个泰波那契数

泰波那契序列 Tn 定义如下:
T0 = 0, T1 = 1, T2 = 1, 且在 n >= 0 的条件下 Tn+3 = Tn + Tn+1 + Tn+2
给你整数 n,请返回第 n 个泰波那契数 Tn 的值。

示例 1:

输入:n = 4
输出:4

解释:

T_3 = 0 + 1 + 1 = 2
T_4 = 1 + 1 + 2 = 4

示例 2:

输入:n = 25
输出:1389537

提示:

0 <= n <= 37
答案保证是一个 32 位整数,即 answer <= 2^31 - 1。

代码:

public static int tribonacci(int n) {
        // 三个数
        int a=0;
        int b=1;
        int c=1;
        if(n==0) return 0;
        if(n==1||n==2) return 1;
        int res=0;
        // count遍历到n的时候结束
        int count=2;
        while (count<n){
            res=a+b+c;
            a=b;
            b=c;
            c=res;
            count++;
        }
        return res;
    }

1138. 字母板上的路径

我们从一块字母板上的位置 (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 仅含有小写英文字母。

思路:遍历target的字符,记录两个字符之间的坐标距离,需要注意的是z点,比如target是"dz"字符串的话,d到z只能是DDDDLLLD而不能是DDDDDLLL!

abcde
fghij
klmno
pqrst
uvwxy
z
public static String alphabetBoardPath(String target) {
        // 前一个字符坐标
        int[] pre={0,0};
        String road="";
        int length=target.length();
        // 遍历target的每个字符
        for(int i=0;i<target.length();i++){
            // 当前字符
            int nowLength=target.charAt(i)-'a';
            // 当前字符对应到字母版上的坐标
            int row=nowLength/5;
            int col=nowLength%5;
            // 刚好找到
            if (row==pre[0]&&col==pre[1]){
                road+="!";
            }else {
                int up=pre[0]-row;
                int left=pre[1]-col;
                // 判断是否为z,如果是z点
                if (row==5&&col==0){
                    // 向下,然后向左
                    int cntLeft=Math.abs(left);
                    int cntDown=Math.abs(up)-1;
                    while (cntDown>0){
                        road+="D";cntDown--;
                    }
                    while (cntLeft>0){
                        road+="L";cntLeft--;
                    }
                    road+="D";
                    road+="!";
                     pre[0]=row;
                    pre[1]=col;
                } // 非z点
                else {
                    if (up>0){
                        while (up>0){
                            road+="U";up--;
                        }
                    }else {
                        while (up<0){
                            road+="D";up++;
                        }
                    }
                    if (left>0){
                        while (left>0){
                            road+="L";left--;
                        }
                    }else {
                        while (left<0){
                            road+="R";left++;
                        }
                    }
                    // 找到之后
                    road+="!";
                    // 更新pre
                    pre[0]=row;
                    pre[1]=col;
                }
            }
        }
        return road;
    }

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:枚举所有的正方形,然后检查四个边,所以当M=N时,这是O(N^4)时间复杂度
  • 方法2:采用预处理矩阵的方法,同样也是枚举所有的正方形,但是判断该正方形是否符合规则是,是O(1)的时间复杂度,所以当M=N时,这是O(N^3)时间复杂度。 这是以空间换时间的做法。

那么如何预处理矩阵呢?
用与原矩阵同样大小的两个矩阵,一个为right,一个为down,right[i][j]表示m[i][j]的右边有多少个连续的1,包括自身;down[i][j]表示m[i][j]的下边有多少个连续的1,包括自身。从右到左,从下到上依次填好两个矩阵。
对于以[row,col]为左上角,length作为边长的正方形,要想四个边全为1,只有满足如下条件:row,col代表左上方的位置,要求左上方处下边最少有连续的length个1,右边最少有连续的length个1;[row + length - 1][col]代表左下角,要求该点右边最少有连续的length个1;[row][col + length - 1]代表右上角,要求该点下边最少有连续的length个1;这样便确立了四个边都符合规则。

参考博客:zjxxyz123的博客

代码:

// 获取最大边长 对于每个边长,看是否存在以该值作为边长的矩阵,满足四周全为1
    public static int largest1BorderedSquare(int[][] grid) {
        int[][] right = new int[grid.length][grid[0].length];
        int[][] down = new int[grid.length][grid[0].length];
        System.out.println("!!!");
        // 设置right和down矩阵
        setRightAndDown(grid, right, down);
        // 因为要找最大边长,所以从大到小找
        for (int length = Math.min(grid.length, grid[0].length); length >= 1; length--) {
            // 判断是否满足存在正方形四周全是1
            if (hasSizeOfBorder(length, right, down)) {
                return length*length;
            }
        }
        return 0;
    }

    // 根据m矩阵,设置right与down矩阵,right[i][j]表示m[i][j]的右边有多少个连续的1,包括自身
    // down[i][j]表示m[i][j]的下边有多少个连续的1,包括自身
    public static void setRightAndDown(int[][] m, int [][] right, int[][] down) {
        int rowNum = m.length;
        int colNum = m[0].length;
        // 初始化右下角位置 1的个数包括自身
        right[rowNum - 1][colNum - 1] = m[rowNum - 1][colNum - 1];
        down[rowNum - 1][colNum - 1] = m[rowNum - 1][colNum - 1];
        // 初始化最后一行 colNum - 2为倒数第二列
        for (int col = colNum - 2; col >= 0; col--) {
            if (m[rowNum - 1][col] == 1) {
                // right数组
                right[rowNum - 1][col] = right[rowNum - 1][col + 1] + 1;
                // down数组
                down[rowNum - 1][col] = 1;
            }
        }
        // 初始化最后一列(row取倒数第二行开始,最后一行的最后一列已经被处理了)
        for (int row = rowNum - 2; row >= 0; row--) {
            if (m[row][colNum - 1] == 1) {
                // right数组
                right[row][colNum - 1] = 1;
                // down数组
                down[row][colNum - 1] = down[row + 1][colNum - 1] + 1;
            }
        }
        // 其他位置,从右向左,从下到上设置值
        for (int row = rowNum - 2; row >= 0; row--) {
            for (int col = colNum - 2; col >= 0; col--) {
                if (m[row][col] == 1) {
                    right[row][col] = right[row][col + 1] + 1;
                    down[row][col] = down[row + 1][col] + 1;
                }
            }
        }
    }


    // 传入一个边长值,根据right与down矩阵,判断是否存在正方形满足四周全为1
    public static boolean hasSizeOfBorder(int length, int[][] right, int[][] down) {
        // row,col代表左上方的位置,要求左上方处下边最少有连续的length个1,右边最少有连续的length个1
        for (int row = 0; row + length - 1 <= right.length - 1; row++) {
            for(int col = 0; col + length - 1 <= right[0].length - 1; col++) {
                // [row + length - 1][col]代表左下角,要求该点右边最少有连续的length个1
                // [row][col + length - 1]代表右上角,要求该点下边最少有连续的length个1
                // 这样四个边都能确定
                if (right[row][col] >= length && down[row][col] >= length
                        && right[row + length - 1][col] >= length
                        && down[row][col + length - 1] >= length) {
                    return true;
                }
            }
        }
        // 没有找到
        return false;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值