5.6 二轮 数组+矩阵+双指针

This commit is contained in:
zhangsan 2025-05-06 14:01:33 +08:00
parent 19b61ceb96
commit 7518637900
7 changed files with 386 additions and 0 deletions

View File

@ -0,0 +1,65 @@
package array;
import java.util.ArrayList;
import java.util.List;
/**
* 题目 6. Z 字形变换 (convert)
* 描述将一个给定字符串 s 根据给定的行数 numRows 以从上往下从左到右进行 Z 字形排列
*
* 比如输入字符串为 "PAYPALISHIRING" 行数为 3 排列如下
*
* P A H N
* A P L S I I G
* Y I R
* 之后你的输出需要从左往右逐行读取产生出一个新的字符串比如"PAHNAPLSIIGYIR"
*
* 请你实现这个将字符串进行指定行数变换的函数
*
* string convert(string s, int numRows);
*
* 示例 1
输入s = "PAYPALISHIRING", numRows = 3
输出"PAHNAPLSIIGYIR"
* 链接https://leetcode.cn/problems/zigzag-conversion/
*/
public class Convert {
public String convert1(String s, int numRows) {
if(numRows==1)return s;
List<List<Character>>lists=new ArrayList<>();
StringBuilder stringBuilder=new StringBuilder();
for (int i = 0; i < numRows; i++) {
lists.add(new ArrayList<>());
}
int level=0,pos=1;
for (int i = 0; i < s.length(); i++) {
if(level==numRows-1)
pos=-1;
else if(level==0)
pos=1;
lists.get(level).add(s.charAt(i));
level+=pos;
}
for (List<Character> list : lists) {
for (Character character : list) {
stringBuilder.append(character);
}
}
return stringBuilder.toString();
}
public String convert(String s, int numRows) {
if(numRows < 2) return s;
List<StringBuilder> rows = new ArrayList<StringBuilder>();
for(int i = 0; i < numRows; i++) rows.add(new StringBuilder());
int i = 0, flag = -1;
for(char c : s.toCharArray()) {
rows.get(i).append(c);
if(i == 0 || i == numRows -1) flag = - flag;
i += flag;
}
StringBuilder res = new StringBuilder();
for(StringBuilder row : rows) res.append(row);
return res.toString();
}
}

View File

@ -0,0 +1,58 @@
package array;
/**
* 题目 151. 反转字符串中的单词 (reverseWords)
* 描述给你一个字符串 s 请你反转字符串中 单词 的顺序
* 单词 是由非空格字符组成的字符串s 中使用至少一个空格将字符串中的 单词 分隔开
* 返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串
* 注意输入字符串 s中可能会存在前导空格尾随空格或者单词间的多个空格返回的结果字符串中单词间应当仅用单个空格分隔且不包含任何额外的空格
*
* 示例 1
输入s = "the sky is blue"
输出"blue is sky the"
* 链接https://leetcode.cn/problems/reverse-words-in-a-string/
*/
public class ReverseWords {
public String reverseWords(String s) {
StringBuilder result = new StringBuilder();
int endIndex = s.length(); // endIndex指向字符串的末尾
int startIndex;
// 遍历字符串按单词逆序拼接
while (endIndex > 0) {
// 找到当前单词的结尾跳过空格
while (endIndex > 0 && s.charAt(endIndex - 1) == ' ') {
endIndex--;
}
// 如果endIndex已经指向开头说明没有更多单词了
if (endIndex == 0) {
break;
}
// 找到当前单词的开始位置
startIndex = endIndex;
while (startIndex > 0 && s.charAt(startIndex - 1) != ' ') {
startIndex--;
}
// 将单词添加到StringBuilder
if (result.length() > 0) {
result.append(" "); // 添加单个空格
}
result.append(s.substring(startIndex, endIndex));
// 更新endIndex准备处理下一个单词
endIndex = startIndex;
}
return result.toString();
}
public static void main(String[] args) {
ReverseWords rw = new ReverseWords();
String s = " the sky is blue ";
System.out.println(rw.reverseWords(s)); // 输出: "blue is sky the"
}
}

View File

@ -0,0 +1,24 @@
package array;
/**
* 题目 28. 找出字符串中第一个匹配项的下标 (strStr)
* 描述给你两个字符串 haystack needle 请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标下标从 0 开始如果 needle 不是 haystack 的一部分则返回 -1
*
* 示例 1
输入haystack = "sadbutsad", needle = "sad"
输出0
解释"sad" 在下标 0 6 处匹配
第一个匹配项的下标是 0 所以返回 0
* 链接https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/
*/
public class StrStr {
public int strStr(String haystack, String needle) {
int sz1=haystack.length();
int sz2=needle.length();
for (int i = 0; i <= sz1-sz2; i++) {
if(haystack.substring(i,i+sz2).equals(needle))
return i;
}
return -1;
}
}

View File

@ -0,0 +1,112 @@
package matrix;
/**
* 题目 289. 生命游戏 (GameOfLife)
* 描述根据 百度百科 生命游戏 简称为 生命 是英国数学家约翰·何顿·康威在 1970 年发明的细胞自动机
*
* 给定一个包含 m × n 个格子的面板每一个格子都可以看成是一个细胞每个细胞都具有一个初始状态 1 即为 活细胞 live 0 即为 死细胞 dead每个细胞与其八个相邻位置水平垂直对角线的细胞都遵循以下四条生存定律
*
* 如果活细胞周围八个位置的活细胞数少于两个则该位置活细胞死亡
* 如果活细胞周围八个位置有两个或三个活细胞则该位置活细胞仍然存活
* 如果活细胞周围八个位置有超过三个活细胞则该位置活细胞死亡
* 如果死细胞周围正好有三个活细胞则该位置死细胞复活
* 下一个状态是通过将上述规则同时应用于当前状态下的每个细胞所形成的其中细胞的出生和死亡是 同时 发生的给你 m x n 网格面板 board 的当前状态返回下一个状态
*
* 给定当前 board 的状态更新 board 到下一个状态
*
* 注意 你不需要返回任何东西
*
* 示例 1
输入board = [[0,1,0],[0,0,1],[1,1,1],[0,0,0]]
输出[[0,0,0],[1,0,1],[0,1,1],[0,1,0]]
* 链接https://leetcode.cn/problems/game-of-life/
*/
public class GameOfLife {
//需要额外空间的解法
void judge(int[][] board,int[][]res,int i,int j){
int[]a={-1,0,1},b={-1,0,1};
int cntoflive=0;
for (int item : a) {
for (int value : b) {
if (item == 0 && value == 0) continue;
int curi = i + item, curj = j + value;
if (curi < 0 || curi >= board.length || curj < 0 || curj >= board[0].length) continue;
if (board[curi][curj] == 1)
cntoflive++;
}
}
if(cntoflive<2||cntoflive>3)
res[i][j]=0;
else if(board[i][j]==0&&cntoflive==3)
res[i][j]=1;
else res[i][j]=board[i][j];
}
public void gameOfLife1(int[][] board) {
int[][]res=new int[board.length][board[0].length];
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
judge(board,res,i,j);
}
}
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
board[i][j]=res[i][j];
}
}
}
/**
* //O(1)空间解法
* -1 表示原来是活1下一代死0
* 2 表示原来是死0下一代活1
*
* 这样第一遍遍历时根据规则把要的活细胞置 -1把要的死细胞置 2第二遍遍历时凡是 >0 的都置 1其余都置 0 即完成更新
* @param board
*/
public void gameOfLife(int[][] board) {
int m = board.length, n = board[0].length;
int[] dirs = {-1, 0, 1};
// 第一遍标记所有要翻转状态的格子
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
int liveNeighbors = 0;
// 数周围 8 个格子的原始状态
for (int dx : dirs) {
for (int dy : dirs) {
if (dx == 0 && dy == 0) continue;
int x = i + dx, y = j + dy;
if (x >= 0 && x < m && y >= 0 && y < n) {
// 原始活细胞是 1 或者标记为 -1原来活后要死
if (board[x][y] == 1 || board[x][y] == -1) {
liveNeighbors++;
}
}
}
}
// 当前是活细胞
if (board[i][j] == 1) {
if (liveNeighbors < 2 || liveNeighbors > 3) {
// 暂标 -1
board[i][j] = -1;
}
}
// 当前是死细胞
else if (board[i][j] == 0) {
if (liveNeighbors == 3) {
// 暂标 2
board[i][j] = 2;
}
}
}
}
// 第二遍把所有格子归一化 0/1
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
board[i][j] = board[i][j] > 0 ? 1 : 0;
}
}
}
}

View File

@ -0,0 +1,82 @@
package matrix;
/**
* 题目 36. 有效的数独 (IsValidSudoku)
* 描述请你判断一个 9 x 9 的数独是否有效只需要 根据以下规则 验证已经填入的数字是否有效即可
*
* 数字 1-9 在每一行只能出现一次
* 数字 1-9 在每一列只能出现一次
* 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次请参考示例图
*注意
*
* 一个有效的数独部分已被填充不一定是可解的
* 只需要根据以上规则验证已经填入的数字是否有效即可
* 空白格用 '.' 表示
*
* 示例 1
输入board =
[["5","3",".",".","7",".",".",".","."]
,["6",".",".","1","9","5",".",".","."]
,[".","9","8",".",".",".",".","6","."]
,["8",".",".",".","6",".",".",".","3"]
,["4",".",".","8",".","3",".",".","1"]
,["7",".",".",".","2",".",".",".","6"]
,[".","6",".",".",".",".","2","8","."]
,[".",".",".","4","1","9",".",".","5"]
,[".",".",".",".","8",".",".","7","9"]]
输出true
* 链接https://leetcode.cn/problems/valid-sudoku/
*/
//没做出来
public class IsValidSudoku {
/**
* 跳过空格
* 对于字符 '.' 直接 continue
*
* 行列宫格索引映射
*
* rows[i][num] 表示第 i 行数字 num 是否出现过
* cols[j][num] 表示第 j 列数字 num 是否出现过
* 宫格 9×9 拆成 9 3×3 宫格 boxIndex = (i/3)*3 + (j/3) boxes[boxIndex][num] 表示该宫格数字 num 是否出现过
* 一次遍历
* 只需对整个板子扫一遍遇到数字就检查对应的三张里是否已标记
*
* 已标记 返回 false
* 未标记 标记为已出现继续扫描
* 遍历结束仍未发现冲突 返回 true
* @param board
* @return
*/
public boolean isValidSudoku(char[][] board) {
// 9 9
boolean[][] rows = new boolean[9][9];
boolean[][] cols = new boolean[9][9];
boolean[][] boxes = new boolean[9][9];
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
char ch = board[i][j];
if (ch == '.') {
continue; // 空格跳过
}
int num = ch - '1'; // 映射到 0..8
// 计算当前格属于哪个 3x3 宫格
int boxIndex = (i / 3) * 3 + (j / 3);
// 如果某行某列或某宫格里已经存在该数字直接返回 false
if (rows[i][num] || cols[j][num] || boxes[boxIndex][num]) {
return false;
}
// 否则就标记为已出现
rows[i][num] = true;
cols[j][num] = true;
boxes[boxIndex][num] = true;
}
}
return true; // 全部检查完毕没有冲突
}
}

View File

@ -0,0 +1,30 @@
package twopointers;
/**
* 题目 167. 两数之和 II - 输入有序数组 (twoSum)
* 描述给你一个下标从 1 开始的整数数组 numbers 该数组已按 非递减顺序排列 请你从数组中找出满足相加之和等于目标数 target 的两个数如果设这两个数分别是 numbers[index1] numbers[index2] 1 <= index1 < index2 <= numbers.length
* 以长度为 2 的整数数组 [index1, index2] 的形式返回这两个整数的下标 index1 index2
* 你可以假设每个输入 只对应唯一的答案 而且你 不可以 重复使用相同的元素
* 你所设计的解决方案必须只使用常量级的额外空间
*
* 示例 1
输入numbers = [2,7,11,15], target = 9
输出[1,2]
解释2 7 之和等于目标数 9 因此 index1 = 1, index2 = 2 返回 [1, 2]
* 链接https://leetcode.cn/problems/two-sum-ii-input-array-is-sorted/
*/
public class TwoSum {
public int[] twoSum(int[] numbers, int target) {
int left=0,right=numbers.length-1;
while(left<right){
int cur=numbers[left]+numbers[right];
if(cur==target)
return new int[]{left+1,right+1};
else if(cur<target)
left++;
else
right--;
}
return new int[]{-1,-1};
}
}

View File

@ -0,0 +1,15 @@
package matrix;
import org.junit.Test;
import static org.junit.Assert.*;
public class GameOfLifeTest {
@Test
public void gameOfLife() {
int[][]board = {{0,1,0},{0,0,1},{1,1,1},{0,0,0}};
GameOfLife solution = new GameOfLife();
solution.gameOfLife(board);
}
}