diff --git a/src/main/java/array/Convert.java b/src/main/java/array/Convert.java new file mode 100644 index 0000000..302d9f6 --- /dev/null +++ b/src/main/java/array/Convert.java @@ -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>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 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 rows = new ArrayList(); + 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(); + } +} diff --git a/src/main/java/array/ReverseWords.java b/src/main/java/array/ReverseWords.java new file mode 100644 index 0000000..bee1623 --- /dev/null +++ b/src/main/java/array/ReverseWords.java @@ -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" + } +} + diff --git a/src/main/java/array/StrStr.java b/src/main/java/array/StrStr.java new file mode 100644 index 0000000..8938aab --- /dev/null +++ b/src/main/java/array/StrStr.java @@ -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; + } +} diff --git a/src/main/java/matrix/GameOfLife.java b/src/main/java/matrix/GameOfLife.java new file mode 100644 index 0000000..01ac64d --- /dev/null +++ b/src/main/java/matrix/GameOfLife.java @@ -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; + } + } + } +} diff --git a/src/main/java/matrix/IsValidSudoku.java b/src/main/java/matrix/IsValidSudoku.java new file mode 100644 index 0000000..0195f38 --- /dev/null +++ b/src/main/java/matrix/IsValidSudoku.java @@ -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; // 全部检查完毕,没有冲突 + } +} diff --git a/src/main/java/twopointers/TwoSum.java b/src/main/java/twopointers/TwoSum.java new file mode 100644 index 0000000..40bdd26 --- /dev/null +++ b/src/main/java/twopointers/TwoSum.java @@ -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