力扣刷题笔记
# 1. 最后一个单词的长度 难易程度: 🌟
题目描述:给你一个字符串 s,由若干单词组成,单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。
单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。
示例 1:
输入:s= "Hello World" | |
输出: 5 | |
解释:最后一个单词是“World”,长度为4。 |
示例 2:
输入:s = " fly me to the moon " | |
输出:4 | |
解释:最后一个单词是“moon”,长度为4。 |
tips:
1 <= s.length <= 104
s
仅有英文字母和空格' '
组成s
中至少存在一个单词
1. 暴力解法:直接使用 API
class Solution { | |
public int lengthOfLastWord(String s) { | |
// 注意提示 s 中至少存在一个单词,如果有一个单词直接返回 | |
if(s.length() == 1) return 1; | |
// 对 s 按照空格进行分割成字符串数组 | |
String[] str = s.split(" "); | |
// 得到数组最后一个字符串 | |
String last = str[str.length -1]; | |
// 返回这个字符串的长度 | |
return last.length(); | |
} | |
-----------分割线--------------------- | |
// 下面是别人的解法:可以学习和参考 | |
public int lengthOfLastWord(String s) { | |
s = s.trim(); | |
return s.length() - s.lastIndexOf(" ") - 1; | |
} | |
-----------官方解法----------------------- | |
public int lengthOfLastWord(String s) { | |
// 反向遍历字符串,寻找最后一个单词并计算其长度。 | |
int index = s.length() - 1; | |
while (s.charAt(index) == ' ') { | |
index--; | |
} | |
int wordLength = 0; | |
// 从最后一个字母开始继续反向遍历字符串,直到遇到空格或者到达字符串的起始位置。 | |
while (index >= 0 && s.charAt(index) != ' ') { | |
wordLength++; | |
index--; | |
} | |
return wordLength; | |
} | |
} |
# 2. 螺旋矩阵 II🌟🌟🌟
题目描述:给你一个正整数 n
,生成一个包含 1
到 n x n
所有元素,且元素按顺时针顺序螺旋排列的 n x n
正方形矩阵 matrix
。
模拟这种层层循环:
- 填充上行从左到右
- 填充右列从上到下
- 填充下行从右到左
- 填充左列从下到上
# 可以举例:n == 3 时:
1. 第一次循环四个方向:坐标每次移动 2 位
2. 还剩一个元素,不用再走四个方向上的移动
# n == 4 时:
1. 第一次循环走 3 步;
2. 第二次循环每次移动 1 步,是在 3 的基础上减去两条已经走过的边;
3. 循环结束,不剩余元素;
# n == 5 时:
1. 第一次循环走 4 步;
2. 第二次循环走 2 步,是在 4 的基础上减去两条已经走过的边;
3. 还剩一个元素,不用再走四个方向上的移动
从上面的举例可以发现规律:
1.n 为奇数时,最里层总会剩下元素没有填充;
n 为偶数时,循环结束所有元素都被填充,不会额外剩下元素;
**2.** 第一层总是走 n-1 步;
第二层总是走上一次循环步数的基础上少 2;
class Solution { | |
public int[][] generateMatrix(int n) { | |
if(n == 1){ // 只有一个元素,直接返回 | |
return new int[][]<!--swig0-->; | |
} | |
int[][] matrix = new int[n][n]; | |
int num = 1; // 数字开始处 | |
int row = 0; // 行坐标 | |
int col = 0; // 列坐标 | |
int count = n /2; // 循环次数 | |
int step = n; // 一次走多少步,第一次为 n, 在循环里面改 step 的值 | |
while( count > 0 ){ | |
// 向左走 n-1 | |
for(int i = 0; i < step - 1;i++){ | |
matrix[row][col++] = num++; //row 不变 col++ | |
} | |
// 向下走 n-1 | |
for(int i = 0; i < step-1; i++){ | |
matrix[row++][col] = num++; //row++,col 不变 | |
} | |
// 向右走 n-1 | |
for(int i = 0; i < step -1;i++){ | |
matrix[row][col--] = num++; //row 不变 col-- | |
} | |
// 向上走 n-1 | |
for(int i = 0; i < step -1 ; i++){ | |
matrix[row--][col] = num++; //row--,col 不变 | |
} | |
step = step-2; // 下一次循环步数 | |
col++; // 列从新的循环位置开始 | |
row++; // 行从新的循环位置开始 | |
count --; // 循环次数减少 | |
} | |
// 如果 n 为奇数,还要再填充一位元素 | |
if(n % 2 == 1){ | |
matrix[row][col] = num; | |
} | |
return matrix; | |
} | |
} |
官方题解思路:之一
模拟矩阵的生成。按照要求,初始位置设为矩阵的左上角,初始方向设为向右。若下一步的位置超出矩阵边界,或者是之前访问过的位置,则顺时针旋转,进入下一个方向。如此反复直至填入 n2 个元素。
记 matrix
为生成的矩阵,其初始元素设为 0。由于填入的元素均为正数,我们可以判断当前位置的元素值,若不为 0,则说明已经访问过此位置。
class Solution { | |
public int[][] generateMatrix(int n) { | |
int maxNum = n * n; | |
int curNum = 1; | |
int[][] matrix = new int[n][n]; | |
int row = 0, column = 0; | |
int[][] directions = <!--swig1-->; // 右下左上 | |
int directionIndex = 0; | |
while (curNum <= maxNum) { | |
matrix[row][column] = curNum; | |
curNum++; | |
// 下一行,下一列的位置 | |
int nextRow = row + directions[directionIndex][0], nextColumn = column + directions[directionIndex][1]; | |
// 下一行列超出了 边界 n, 就旋转方向 | |
if (nextRow < 0 || nextRow >= n || nextColumn < 0 || nextColumn >= n || matrix[nextRow][nextColumn] != 0) { | |
directionIndex = (directionIndex + 1) % 4; // 顺时针旋转至下一个方向 | |
} | |
// 行和列位置移动 | |
row = row + directions[directionIndex][0]; | |
column = column + directions[directionIndex][1]; | |
} | |
return matrix; | |
} | |
} |
# 一定要会的 DFS
这是一套模板,很多地方都会用到这个思想
1. 从左上角开始移动,方向依次向右、向下、向左、向上、向右
2. 转向的条件是撞到墙:定义墙是:到达某边界 和 到达某遍历过的格子
3. 撞墙时,我们需要改变行走方向
class Solution { | |
// 定义移动方向,右,下,左,上 | |
public static int[] dx = {1, 0, -1, 0}; | |
public static int[] dy = {0, 1, 0, -1}; | |
// 定义行走方向 | |
int direction = 0; | |
// 定义返回结果 | |
public static int[][] res; | |
public int[][] generateMatrix(int n) { | |
// 初始化二维数组大小 | |
res = new int[n][n]; | |
dfs(n, 0, 0, 1); | |
return res; | |
} | |
// 深度优先搜索:递归 | |
public void dfs(int n, int x, int y, int num) { | |
// 判断条件:超出边界,或者遇到已经赋值过的方格 | |
if (x < 0 || x >= n || y < 0 || y >= n || res[y][x] != 0) { | |
// 撞到墙了,需要转向 | |
direction++; | |
// 如果已经转了一圈,需要从头开始如 dir = 4,需要再从 0 即向右移动 | |
direction %= 4; | |
return; | |
} | |
// 每次给该方格赋值 | |
res[y][x] = num; | |
// 循环供一次原方向,一次转向 | |
for (int i = 0; i < 2; i++) { | |
// 位移 | |
int mx = x + dx[direction]; | |
int my = y + dy[direction]; | |
// 递归下一个方格 | |
dfs(n, mx, my, num + 1); | |
} | |
} | |
} |
总结:1. 尽量少用现成 API;
2. 在第一次暴力求解的基础上,去考虑时间和空间优化问题;
3. 例如类似于第二个螺旋矩阵的题,可以使用 DFS 算法