LeeCode数据结构热题
较热门的中等算法题,仅作学习记录。
Solution36有效的数独、Solution37解数独、Solution46全排列、Solution50Pow(x,n)、Solution73矩阵置零、Solution289生命游戏、
Solution36有效的数独
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解数独
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;
}
}