LeeCode数据结构热题
较热门的中等算法题,仅作学习记录。
Solution5最长回文子串、Solution36有效的数独、Solution37解数独、Solution46全排列、Solution50Pow(x,n)、Solution73矩阵置零、Solution289生命游戏、Solution152乘积最大的子数组和、
Solution5最长回文子串
给你一个字符串 s,找到 s 中最长的回文子串。
示例 1:
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
示例 2:输入:s = "cbbd"
输出:"bb"
class Solution {
public String longestPalindrome(String s) {
String res = " ";
for(int i= 0; i < s.length(); i++){
//以s[i]为中心的子串
String s1 = palindrome(s,i,i);
//
String s2 = palindrome(s,i,i+1);
//
res = res.length() > s1.length() ? res : s1;
res = res.length() > s2.length() ? res : s2;
}
return res;
}
public String palindrome(String s, int l, int r){
//防越界
while(l >= 0 && r < s.length() && s.charAt(l) == s.charAt(r)){
//双指针,中间向两边展开
l--; r++;
}
return s.substring(l+1, r);
}
}
Solution36有效的数独
请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
class Solution {
public boolean isValidSudoku(char[][] board) {
boolean[][] row = new boolean[9][10];//行
boolean[][] col = new boolean[9][10];//列
boolean[][] bucket = new boolean[9][10];//桶
for(int i = 0; i < 9; i++){
for(int j = 0; j < 9; j++){
//i,j每个格子,i行 j列 bucket桶 bid计算当前桶号
int bid = 3*(i/3) + (j/3);
if(board[i][j] != '.'){
int num = board[i][j] - '0';
if(row[i][num] || col[j][num] || bucket[bid][num]){
return false;
}
row[i][num] = true;
col[j][num] = true;
bucket[bid][num] = true;
}
}
}
return true;
}
}
Solution37解数独
编写一个程序,通过填充空格来解决数独问题。
数独的解法需 遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
数独部分空格内已填入了数字,空白格用 '.' 表示。图同上
class Solution {
public static void solveSudoku(char[][] board){
boolean[][] row = new boolean[9][10];
boolean[][] col = new boolean[9][10];
boolean[][] bucket = new boolean[9][10];
initMaps(board, row, col, bucket);
process(board, 0, 0, row, col, bucket);
}
private static void initMaps(char[][] board, boolean[][] row, boolean[][] col, boolean[][] bucket) {
for(int i = 0; i < 9; i++){
for(int j = 0; j < 9; j++){
int bid = 3 *(i / 3) + (j / 3);
if(board[i][j] != '.'){
int num = board[i][j] - '0';
row[i][num] = true;
col[j][num] = true;
bucket[bid][num] = true;
}
}
}
}
//当前来到i行j列这个位置,如果以及有数字,跳到下一个位置
// 如果没有数字,尝试1~9,不能和row/col/bucket冲突
public static boolean process(char[][] board, int i, int j, boolean[][] row, boolean[][] col, boolean[][] bucket) {
if(i == 9){
return true;
}
//该切下一行下一位的坐标
int nexti = j != 8 ? i : i+1;
int nextj = j != 8 ? j + 1 : 0;
if(board[i][j] != '.'){//直接下一位
return process(board, nexti, nextj, row, col, bucket);
}else {
//可以尝试1~9
int bid = 3 * (i/3) + (j/3);
for(int num = 1; num <= 9; num++){
if((!row[i][num]) && (!col[j][num]) && (!bucket[bid][num])){
//可以尝试num
row[i][num] = true;
col[j][num] = true;
bucket[bid][num] = true;
board[i][j] = (char)(num + '0');
if(process(board, nexti, nextj, row, col, bucket)){
return true;
}
//清除状态 恢复现场
row[i][num] = false;
col[j][num] = false;
bucket[bid][num] = false;
board[i][j] = '.';
}
}
}
return false;
}
}
Solution46全排列
回溯算法 类似遍历多叉树,选择
class Solution {
//建新表存储全排列结果
List<List<Integer>> res = new LinkedList<>();
public List<List<Integer>> permute(int[] nums) {
//记录路径
LinkedList<Integer> track = new LinkedList<>();
backtrack(nums,track);
return res;
}
public void backtrack(int[] nums, LinkedList<Integer> track){
//到达叶子节点,就将路径装进结果
if(track.size() == nums.length){
//只传track是地址引用
res.add(new LinkedList(track));
return;
}
for(int i = 0; i < nums.length; i++){
//排除相同选项
if(track.contains(nums[i])){
continue;
}
//做选择
track.add(nums[i]);
//进入下一层决策
backtrack(nums, track);
//取消选择
track.removeLast();
}
}
}
dfs加递归处理
class Solution {
List<List<Integer>> ans;
boolean[] visited;
public List<List<Integer>> permute(int[] nums) {
ans = new ArrayList<>();
visited = new boolean[nums.length];
dfs2(nums,0,new ArrayList<>());
// dfs1(nums,0,new ArrayList<>());
return ans;
}
//每轮将一个未访问过的元素加入结果
//idx:当前需要确定元素的下标位置
private void dfs1(int[] nums,int idx,List<Integer> temp){
if(idx == nums.length) ans.add(new ArrayList<>(temp));
for(int i = 0;i < nums.length; ++i){
if(!visited[i]){
temp.add(nums[i]);
visited[i] = true;
dfs1(nums,idx+1,temp);
visited[i] = false;
temp.remove(temp.size()-1);
}
}
}
//将idx及后面元素交换到待排序列头部(idx下标位置),递归处理剩余部分
//idx:当前待排序列头部
private void dfs2(int[] nums,int idx,List<Integer> temp){
if(idx == nums.length) ans.add(new ArrayList<>(temp));
for(int i = idx; i < nums.length; ++i){
swap(nums,idx,i);
temp.add(nums[idx]);
dfs2(nums,idx+1,temp);
swap(nums,idx,i);
temp.remove(temp.size()-1);
}
}
private void swap(int[] nums, int i, int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
Solution50Pow(x,n)
Solution73矩阵置零
像是炸弹人,使第一列当作标记列,注意找出第一行第一列的0最后置零。
class Solution {
public void setZeroes(int[][] matrix) {
boolean col0 = false;
int i = 0;
int j = 0;
for(i = 0; i < matrix.length; i++){
for(j = 0; j < matrix[0].length; j++){
if(matrix[i][j] == 0){
matrix[i][0] = 0;
if( j == 0 ){
col0 = true;
}else{
matrix[0][j] = 0;
}
}
}
}
//用首行列修改矩阵里的0
for(i = matrix.length -1; i >= 0; i--){
for(j = 1; j < matrix[0].length; j++){
if(matrix[i][0] == 0 || matrix[0][j] == 0){
matrix[i][j] = 0;
}
}
}
//修改0列
if(col0){
for(i = 0; i < matrix.length; i++){
matrix[i][0]= 0;
}
}
}
}
Solution289生命游戏
用原始空间完成辅助数组作用,使用32位最后1位表示1或0,用倒数第二位表示下一轮是死是活。
class Solution {
public void gameOfLife(int[][] board) {
int N = board.length;
int M = board[0].length;
for(int i = 0; i<N; i++){
for(int j = 0; j<M; j++){
//拿到周围邻居数
int neighbors = neighbors(board,i,j);
//找到下轮必活的位置给第二位标1, 即 |=2
if(neighbors == 3 || (board[i][j] == 1 && neighbors == 2)){
board[i][j] |= 2;
}
}
}
for(int i = 0; i < N; i++){
for(int j = 0; j < M; j++){
board[i][j] >>= 1;
}
}
}
public static int neighbors(int[][] b, int i, int j){
//遍历八个方向找到邻居个数
return f(b, i - 1, j - 1)
+ f(b, i - 1, j)
+ f(b, i - 1, j + 1)
+ f(b, i, j - 1)
+ f(b, i, j + 1)
+ f(b, i + 1, j)
+ f(b, i + 1, j - 1)
+ f(b, i + 1, j + 1);
}
//b[i][j] 有1返回1,不是1就返回0
public static int f(int[][] b, int i, int j){
//判断边界跟修改的最后两位是不是1 而返回01值
return (i >= 0 && i < b.length && j >= 0 && j < b[0].length && (b[i][j] & 1) == 1)
? 1 : 0;
}
}
Solution152乘积最大的子数组和
给你一个整数数组 nums ,请你找出数组中乘积最大的非空连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
测试用例的答案是一个 32-位 整数。
子数组 是数组的连续子序列。
class Solution {
public int maxProduct(int[] nums) {
if(nums == null || nums.length == 0){
return 0;
}
int n = nums.length;
//上一步最大值
int premax = nums[0];
//上一步最小值
int premin = nums[0];
int ans = nums[0];
for(int i = 1;i < n; i++){
int p1 = nums[i];
int p2 = nums[i] * premax;
int p3 = nums[i] * premin;
int curmax = Math.max(Math.max(p1,p2),p3);
int curmin = Math.min(Math.min(p1,p2),p3);
ans = Math.max(ans,curmax);
//重置变量下一轮直接用
premax = curmax;
premin = curmin;
}
return ans;
}
}