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!
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 |
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;
}