Skip to content

Commit 79f4904

Browse files
committed
补充 hot 100 medium 题解
1 parent dd5f4c5 commit 79f4904

File tree

9 files changed

+482
-0
lines changed

9 files changed

+482
-0
lines changed

src/com/alibaba/edison/AlgorithmDataStructure.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
* offer/add添加元素;peek返回队列的头部元素,但是不出队;poll/remove返回并删除队列的头部元素。
1111
* [优先队列(PriorityQueue)常用方法及简单案例](https://blog.csdn.net/m0_37602827/article/details/100172976)
1212
* 6.PriorityBlockingQueue,线程安全版PriorityQueue,多线程环境,会阻塞其余线程
13+
* 3.Queue(队列)->Deque(双端队列)->ArrayDeque,内部是数组
1314
*
1415
*
1516
* 位运算
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package com.alibaba.edison;
2+
3+
import java.util.ArrayList;
4+
import java.util.Comparator;
5+
import java.util.List;
6+
import java.util.PriorityQueue;
7+
8+
/**
9+
* 合并区间,medium
10+
* 以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回一个不重叠的
11+
* 区间数组,该数组需恰好覆盖输入中的所有区间。
12+
* <p>
13+
* <p>
14+
* author: qonyqian
15+
* created on: 2022/2/7 11:17 下午
16+
* version:1.0
17+
* description:
18+
*/
19+
public class LeetCode56 {
20+
21+
/**
22+
* 这种类型的题,没有套路。就是分析规律,然后用代码实现。
23+
*
24+
* @param intervals
25+
* @return
26+
*/
27+
public int[][] merge(int[][] intervals) {
28+
//分析规律:先排序,再遍历
29+
PriorityQueue<int[]> queue = new PriorityQueue<>(new Comparator<int[]>() {
30+
@Override
31+
public int compare(int[] o1, int[] o2) {
32+
return o1[0] - o2[0]; //升序
33+
}
34+
});
35+
int length = intervals.length;
36+
for (int i = 0; i < length; i++) {
37+
queue.add(intervals[i]);
38+
}
39+
List<int[]> result = new ArrayList<>();
40+
int[] temp = queue.poll();
41+
while (!queue.isEmpty()) {
42+
int[] next = queue.poll();
43+
if (temp[1] >= next[1]) { //前一个区间完全包围后一个区间
44+
temp = new int[]{temp[0], temp[1]}; //扩大范围,向后继续探索
45+
} else if (temp[1] >= next[0]) { //建一个区间与后一个区间存在交集
46+
temp = new int[]{temp[0], next[1]}; //扩大范围,向后继续探索
47+
} else { //前一个区间与后一个区间,没有交集
48+
result.add(temp); //前一个区间探索完毕,添加到结果列表
49+
temp = next; //把下一个区间设置为探索区间,继续下一个循环
50+
}
51+
}
52+
result.add(temp); //集合已经遍历完成,把最有一个区间添加到结果列表
53+
int[][] array = new int[result.size()][]; //把list转化为数组
54+
return result.toArray(array);
55+
}
56+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package com.alibaba.edison;
2+
3+
/**
4+
* 不同路径,medium
5+
* 一个机器人位于一个 m x n网格的左上角 (起始点在下图中标记为 “Start” )。
6+
* 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
7+
* 问总共有多少条不同的路径?
8+
* <p>
9+
* author: qonyqian
10+
* created on: 2022/2/8 1:36 下午
11+
* version:1.0
12+
* description:
13+
*/
14+
public class LeetCode62 {
15+
16+
/**
17+
* 经典的动态规划
18+
* <p>
19+
* 由于机器人只能向右走和向下走,所以要想到达(m,n),必须先到达(m,n-1)或(m-1,n)
20+
* dp[i][j],表示到达(i,j)的总路径
21+
* 状态转移方程:dp[i][j] = dp[i][j-1] + dp[i-1][j]
22+
* 边界条件:在左边和上边,只有一种走法
23+
*
24+
* @param m
25+
* @param n
26+
* @return
27+
*/
28+
public int uniquePaths(int m, int n) {
29+
if (m == 1 || n == 1) {
30+
return 1;
31+
}
32+
int[][] dp = new int[m][n];
33+
dp[0][0] = 0;
34+
for (int i = 0; i < m; i++) {
35+
for (int j = 0; j < n; j++) {
36+
if (i == 0) {
37+
dp[i][j] = 1;
38+
} else if (j == 0) {
39+
dp[i][j] = 1;
40+
} else {
41+
dp[i][j] = dp[i][j - 1] + dp[i - 1][j];
42+
}
43+
}
44+
}
45+
return dp[m - 1][n - 1];
46+
}
47+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.alibaba.edison;
2+
3+
/**
4+
* 最小路径和,medium
5+
* 给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
6+
* 说明:每次只能向下或者向右移动一步。
7+
* <p>
8+
* 与LeetCode62,同样的思路
9+
* <p>
10+
* author: qonyqian
11+
* created on: 2022/2/8 2:32 下午
12+
* version:1.0
13+
* description:
14+
*/
15+
public class LeetCode64 {
16+
17+
/**
18+
* 凭直觉是动态规划
19+
* <p>
20+
* dp[i][j] 表示 到达(i,j)的路径和
21+
* 状态转移方程:dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j] ,只能向下和向右移动
22+
*
23+
* @param grid
24+
* @return
25+
*/
26+
public int minPathSum(int[][] grid) {
27+
int m = grid.length;
28+
int n = grid[0].length;
29+
int[][] dp = new int[m][n];
30+
for (int i = 0; i < m; i++) { //因为只能向下和向右移动,所以可以使用循环,因为循环也是按照从做到右,从上到下的顺序。使前面的计算结果正好可以给后面复用
31+
for (int j = 0; j < n; j++) {
32+
if (i == 0 && j == 0) { // 初始值
33+
dp[0][0] = grid[0][0];
34+
} else if (i == 0) { //上边
35+
dp[i][j] = dp[i][j - 1] + grid[i][j];
36+
} else if (j == 0) { //左边
37+
dp[i][j] = dp[i - 1][j] + grid[i][j];
38+
} else {
39+
dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
40+
}
41+
}
42+
}
43+
return dp[m - 1][n - 1];
44+
}
45+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.alibaba.edison;
2+
3+
/**
4+
* 颜色分类,medium
5+
* 给定一个包含红色、白色和蓝色、共n 个元素的数组nums,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
6+
* 我们使用整数 0、1 和 2 分别表示红色、白色和蓝色。
7+
* 必须在不使用库的sort函数的情况下解决这个问题。
8+
* <p>
9+
* author: qonyqian
10+
* created on: 2022/2/8 3:06 下午
11+
* version:1.0
12+
* description:
13+
*/
14+
public class LeetCode75 {
15+
16+
/**
17+
* 1.直接单个元素暴力冒泡
18+
* 2.没有套路,只能分析规律,然后实现。双指针+团体冒泡。
19+
*
20+
* @param nums
21+
*/
22+
public void sortColors(int[] nums) {
23+
//团体冒泡,使目标团体一直紧贴着next元素,一步一步把目标团体冒上去。
24+
for (int i = 2; i > 0; i--) { //一共三种元素,当把 2 和 1 排好了,0 自然也就排好了,所以只需要两次循环
25+
int left = -1, right = -1; //双指针
26+
for (int j = 0; j < nums.length; j++) { //开始团体冒泡
27+
if (nums[j] == i) { //next是目标元素
28+
if (left == -1) { //以前未发现目标团体,则直接更新双指针
29+
left = j;
30+
right = j;
31+
} else { //以前发现了目标团体,直接扩充移动右边界指针,扩充团体
32+
right = j;
33+
}
34+
} else if (nums[j] < i) { //next比目标元素小,所以应该把它移动团体的左边
35+
if (left == -1) { //左边还没有目标团体
36+
continue;
37+
} else { //左边已有目标团体,直接交换左指针和next
38+
int temp = nums[j];
39+
nums[j] = nums[left];
40+
nums[left] = temp;
41+
left++; //更新边界指针
42+
right++; //更新边界指针
43+
}
44+
} else { //因为我们是先排大元素,再排小元素,所以如果遇到比目标团体大的next,说明已经后面已经都是排好序的元素,那么就直接结束本次冒泡
45+
break;
46+
}
47+
}
48+
}
49+
}
50+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.alibaba.edison;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
/**
7+
* 子集,medium
8+
* 给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
9+
* 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
10+
* <p>
11+
* author: qonyqian
12+
* created on: 2022/2/8 3:59 下午
13+
* version:1.0
14+
* description:
15+
*/
16+
public class LeetCode78 {
17+
18+
/**
19+
* 又是探索所有的解,自然就会想到回溯法
20+
*
21+
* @param nums
22+
* @return
23+
*/
24+
public List<List<Integer>> subsets(int[] nums) {
25+
List<List<Integer>> result = new ArrayList<>();
26+
result.add(new ArrayList<>()); //空集也是子集
27+
List<Integer> combine = new ArrayList<>();
28+
recursion(result, combine, nums, 0);
29+
return result;
30+
}
31+
32+
/**
33+
* 递归探索
34+
* @param result
35+
* @param combine
36+
* @param nums
37+
* @param index 从第几个元素开始探索
38+
*/
39+
public void recursion(List<List<Integer>> result, List<Integer> combine, int[] nums, int index) {
40+
for (int i = index; i < nums.length; i++) {
41+
combine.add(nums[i]);
42+
List<Integer> temp = new ArrayList<>();
43+
temp.addAll(combine);
44+
result.add(temp); //每探索一步,都是一个子集
45+
recursion(result, combine, nums, i + 1); //因为不能包含重复的元素,所以用过的元素就不能再用了,要从 i + 1 开始探索
46+
combine.remove(combine.size() - 1); //回溯,探索另一条岔路
47+
}
48+
}
49+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package com.alibaba.edison;
2+
3+
/**
4+
* 单词搜索,medium
5+
* 给定一个m x n 二维字符网格 board 和一个字符串单词word 。如果word 存在于网格中,返回 true ;否则,返回 false 。
6+
* 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
7+
* <p>
8+
* <p>
9+
* author: qonyqian
10+
* created on: 2022/2/8 5:11 下午
11+
* version:1.0
12+
* description:
13+
*/
14+
public class LeetCode79 {
15+
16+
/**
17+
* 这题好难呀,乍一看,完全没有思路
18+
* <p>
19+
* 不过这种探索类型的题目,没想法时,用回溯法准没错
20+
*
21+
* @param board
22+
* @param word
23+
* @return
24+
*/
25+
public boolean exist(char[][] board, String word) {
26+
int m = board.length;
27+
int n = board[0].length;
28+
boolean[][] visited = new boolean[m][n];
29+
for (int i = 0; i < m; i++) {
30+
for (int j = 0; j < n; j++) { //以每个点为起点,依次探索
31+
recursion(visited, m, n, i, j, board, word, 0); //递归探索
32+
if (find) { //如果找到了,提前返回。
33+
return true;
34+
}
35+
}
36+
}
37+
return false;
38+
}
39+
40+
boolean find = false;
41+
42+
/**
43+
* 递归探索单次
44+
*
45+
* @param visited
46+
* @param m 矩阵的行
47+
* @param n 矩阵的列
48+
* @param x 将要探索元素的坐标
49+
* @param y 将要探索元素的坐标
50+
* @param board
51+
* @param word
52+
* @param index 探索 word 的第几个字符
53+
*/
54+
public void recursion(boolean[][] visited, int m, int n, int x, int y, char[][] board, String word, int index) {
55+
if (find) { //如果已经找到了,提前返回
56+
return;
57+
}
58+
if (index == word.length()) { //word 已经探索完,成功找到
59+
find = true;
60+
return;
61+
}
62+
if (x < 0 || x > m - 1 || y < 0 || y > n - 1) { //元素坐标非法
63+
return;
64+
}
65+
if (visited[x][y]) { //这个点已经探索过了,不能重复探索
66+
return;
67+
}
68+
if (board[x][y] != word.charAt(index)) { //元素与 word 的字符不等
69+
return;
70+
}
71+
visited[x][y] = true; //更新元素已经探索过
72+
recursion(visited, m, n, x - 1, y, board, word, index + 1); //继续探索它的上
73+
recursion(visited, m, n, x, y + 1, board, word, index + 1); //右
74+
recursion(visited, m, n, x + 1, y, board, word, index + 1); //下
75+
recursion(visited, m, n, x, y - 1, board, word, index + 1); //左
76+
visited[x][y] = false; //回溯,恢复元素为未探索状态
77+
}
78+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.alibaba.edison;
2+
3+
/**
4+
* 不同的二叉搜索树,medium
5+
* 给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。
6+
*
7+
* 二叉查找树(英语:Binary Search Tree),也称为二叉搜索树、二叉查找树、有序二叉树(ordered binary tree)或排序二叉
8+
* 树(sorted binary tree),是指一棵空树或者具有下列性质的二叉树:
9+
* 1.若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
10+
* 2.若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
11+
* 3.任意节点的左、右子树也分别为二叉查找树;
12+
*
13+
* 未能独立解答
14+
*
15+
* author: qonyqian
16+
* created on: 2022/2/8 7:39 下午
17+
* version:1.0
18+
* description:
19+
*/
20+
public class LeetCode96 {
21+
22+
/**
23+
* 二叉搜索树的中序遍历是升序的
24+
*
25+
* 感觉又是回溯法,探索所有可能。【卧槽,竟然是动态规划】
26+
*
27+
* @param n
28+
* @return
29+
*/
30+
public int numTrees(int n) {
31+
int[] G = new int[n + 1];
32+
G[0] = 1;
33+
G[1] = 1;
34+
35+
for (int i = 2; i <= n; ++i) {
36+
for (int j = 1; j <= i; ++j) {
37+
G[i] += G[j - 1] * G[i - j];
38+
}
39+
}
40+
return G[n];
41+
}
42+
}

0 commit comments

Comments
 (0)