Skip to content

Commit c53ebf7

Browse files
committed
update codes
1 parent 48d5b11 commit c53ebf7

File tree

10 files changed

+360
-41
lines changed

10 files changed

+360
-41
lines changed

README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,21 @@
99

1010
<h1 align="center">algorithm-tutorial</h1>
1111

12-
> 算法、数据结构这类知识点真的需要天分。本人不是算法工程师,也做不了算法工程师。总是在见识到一些算法大神的优雅实现后,感叹于自己是多么的弱智,同样是写代码,我写的是什么垃圾!
12+
> 算法、数据结构学习要点:
1313
>
14-
> 这个项目的初衷,是将工作中经常会接触到的一些数据结构和算法整理归纳。人总是要有理想的,要想少写垃圾的代码,必须夯实算法的基础。路漫漫兮其修远,吾将上下而求索。
14+
> 三分学,七分练
15+
>
16+
> 坚持 + 坚持 + 坚持
1517
>
1618
> 🔁 项目同步维护在 [github](https://github.com/dunwu/algorithm-tutorial) | [gitee](https://gitee.com/turnon/algorithm-tutorial)
1719
>
1820
> 📖 [电子书](https://dunwu.github.io/algorithm-tutorial/) | [电子书(国内)](http://turnon.gitee.io/algorithm-tutorial/)
1921
2022
## 内容
2123

24+
![img](http://dunwu.test.upcdn.net/snap/20200702071922.png)
25+
26+
- [算法概述](docs/overview.md)
2227
- [数组](docs/array.md)
2328
- [链表](docs/list.md)
2429
- [](docs/stack.md)
@@ -127,6 +132,7 @@
127132

128133
#### 二叉树
129134

135+
- [二叉搜索树的最近公共祖先](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉搜索树的最近公共祖先.java)
130136
- [二叉搜索树节点最小距离](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉搜索树节点最小距离.java)
131137
- [二叉树的层次遍历](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树的层次遍历.java)
132138
- [二叉树的层次遍历 2](https://github.com/dunwu/algorithm-tutorial/blob/master/codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/btree/二叉树的层次遍历2.java)

assets/算法.xmind

421 KB
Binary file not shown.
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package io.github.dunwu.algorithm.divide;
2+
3+
import org.junit.jupiter.api.Assertions;
4+
5+
/**
6+
* 50. Pow(x, n) 求 N次幂
7+
*
8+
* @author <a href="mailto:forbreak@163.com">Zhang Peng</a>
9+
* @see <a href="https://leetcode-cn.com/problems/powx-n/">50. Pow(x, n)</a>
10+
* @since 2020-07-02
11+
*/
12+
public class N次幂 {
13+
14+
public static void main(String[] args) {
15+
Assertions.assertEquals(1024.00000, myPow(2.00000, 10));
16+
Assertions.assertEquals(9.261000000000001, myPow(2.10000, 3));
17+
Assertions.assertEquals(0.25000, myPow(2.00000, -2));
18+
19+
Assertions.assertEquals(1024.00000, myPow2(2.00000, 10));
20+
Assertions.assertEquals(9.261000000000001, myPow2(2.10000, 3));
21+
Assertions.assertEquals(0.25000, myPow2(2.00000, -2));
22+
}
23+
24+
/**
25+
* 分治算法
26+
* <p>
27+
* x^n 可以视为 y^2(n为偶数) 或 x*y^2(n为奇数)
28+
* <p>
29+
* 时间复杂度:O(log N)
30+
*/
31+
public static double myPow(double x, int n) {
32+
if (n > 0) return helper(x, n);
33+
return 1.00000 / helper(x, -n);
34+
}
35+
36+
public static double helper(double x, int n) {
37+
if (n == 0) {
38+
return 1.00000;
39+
}
40+
41+
double y = helper(x, n / 2);
42+
if (n % 2 == 0) {
43+
return y * y;
44+
} else {
45+
return x * y * y;
46+
}
47+
}
48+
49+
/**
50+
* 暴力破解法
51+
* <p>
52+
* 时间复杂度:O(N)
53+
*/
54+
public static double myPow2(double x, int n) {
55+
double result = 1.00000;
56+
57+
if (n == 0) {
58+
return 1.00000;
59+
}
60+
61+
int cnt = n > 0 ? n : -n;
62+
for (int i = 0; i < cnt; i++) {
63+
result *= x;
64+
}
65+
66+
if (n < 0) result = 1.00000 / result;
67+
return result;
68+
}
69+
70+
// 库函数
71+
public static double myPow3(double x, int n) {
72+
return Math.pow(x, n);
73+
}
74+
75+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/**
2+
* 分治算法
3+
*
4+
* @author <a href="mailto:forbreak@163.com">Zhang Peng</a>
5+
* @since 2020-07-02
6+
*/
7+
package io.github.dunwu.algorithm.divide;
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package io.github.dunwu.algorithm.divide;
2+
3+
import org.junit.jupiter.api.Assertions;
4+
5+
import java.util.Arrays;
6+
7+
/**
8+
* 多数元素
9+
*
10+
* @author <a href="mailto:forbreak@163.com">Zhang Peng</a>
11+
* @see <a href="https://leetcode-cn.com/problems/majority-element/">多数元素</a>
12+
* @since 2020-07-02
13+
*/
14+
public class 多数元素 {
15+
16+
public static void main(String[] args) {
17+
Assertions.assertEquals(3, majorityElement(new int[] { 3, 2, 3 }));
18+
Assertions.assertEquals(2, majorityElement(new int[] { 2, 2, 1, 1, 1, 2, 2 }));
19+
Assertions.assertEquals(6, majorityElement(new int[] { 6, 6, 6, 7, 7 }));
20+
}
21+
22+
// 暴力破解法
23+
// 时间复杂度:O(N) + O(log N)
24+
public static int majorityElement(int[] nums) {
25+
Arrays.sort(nums);
26+
int max = 1;
27+
int count = 0;
28+
int currElem = nums[0];
29+
int maxElem = nums[0];
30+
for (int i = 0; i < nums.length; i++) {
31+
if (nums[i] != currElem) {
32+
count = 1;
33+
currElem = nums[i];
34+
} else {
35+
count++;
36+
if (maxElem == currElem) {
37+
max = count;
38+
} else {
39+
if (max < count) {
40+
maxElem = currElem;
41+
}
42+
}
43+
}
44+
}
45+
return maxElem;
46+
}
47+
48+
}

codes/algorithm/src/main/java/io/github/dunwu/algorithm/tree/TreeUtils.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ public static TreeNode buildTree(Integer... array) {
5656
}
5757
}
5858

59+
public static TreeNode find(TreeNode root, int val) {
60+
if (root == null || root.val == val) { return root;}
61+
TreeNode left = find(root.left, val);
62+
if (left != null) return left;
63+
return find(root.right, val);
64+
}
65+
5966
public static void depthOrderTraverse(TreeNode root) {
6067
if (root == null) {
6168
return;
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package io.github.dunwu.algorithm.tree.btree;
2+
3+
import io.github.dunwu.algorithm.tree.TreeUtils;
4+
import org.junit.jupiter.api.Assertions;
5+
6+
/**
7+
* <code>235. 二叉搜索树的最近公共祖先</code> 算法实现
8+
*
9+
* @see 二叉树的最近公共祖先 可以使用二叉树的最近公共祖先,但没有利用二叉搜索树特性,性能略差
10+
* @see <a href="https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree/">235. 二叉搜索树的最近公共祖先</a>
11+
*/
12+
public class 二叉搜索树的最近公共祖先 {
13+
14+
public static void main(String[] args) {
15+
TreeNode root = TreeUtils.buildTree(6, 2, 8, 0, 4, 7, 9, null, null, 3, 5);
16+
TreeNode p = TreeUtils.find(root, 2);
17+
TreeNode q = TreeUtils.find(root, 8);
18+
// TreeNode treeNode = lowestCommonAncestor(root, p, q);
19+
TreeNode treeNode = lowestCommonAncestor2(root, p, q);
20+
Assertions.assertNotNull(treeNode);
21+
Assertions.assertEquals(6, treeNode.val);
22+
System.out.println("公共祖先节点 = " + treeNode.val);
23+
24+
TreeNode root2 = TreeUtils.buildTree(6, 2, 8, 0, 4, 7, 9, null, null, 3, 5);
25+
TreeNode p2 = TreeUtils.find(root2, 2);
26+
TreeNode q2 = TreeUtils.find(root2, 4);
27+
// TreeNode treeNode2 = lowestCommonAncestor(root2, p2, q2);
28+
TreeNode treeNode2 = lowestCommonAncestor2(root2, p2, q2);
29+
Assertions.assertNotNull(treeNode2);
30+
Assertions.assertEquals(2, treeNode2.val);
31+
System.out.println("公共祖先节点 = " + treeNode2.val);
32+
}
33+
34+
/**
35+
* 递归方式求解
36+
* <p>
37+
* 时间复杂度:O(N) 线性级
38+
* <p>
39+
* 空间复杂度:O(2) 常数级
40+
*/
41+
public static TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
42+
// 如果当前节点为空,直接返回
43+
// 或当前节点就是 p 或 q 其中一个,显然就是要找的最近公共祖先,直接返回
44+
if (root == null || root == p || root == q) return root;
45+
46+
if (root.val > p.val && root.val > q.val) { // 如果当前节点值同时大于 p、q 的值,说明 p、q 肯定都在左子树
47+
return lowestCommonAncestor(root.left, p, q);
48+
} else if (root.val < p.val && root.val < q.val) { // 如果当前节点值同时小于 p、q 的值,说明 p、q 肯定都在右子树
49+
return lowestCommonAncestor(root.right, p, q);
50+
} else {
51+
return root;
52+
}
53+
}
54+
55+
/**
56+
* 非递归方式求解
57+
* <p>
58+
* 时间复杂度:O(N) 线性级
59+
* <p>
60+
* 空间复杂度:O(2) 常数级
61+
*/
62+
public static TreeNode lowestCommonAncestor2(TreeNode root, TreeNode p, TreeNode q) {
63+
// 如果当前节点为空,直接返回
64+
// 或当前节点就是 p 或 q 其中一个,显然就是要找的最近公共祖先,直接返回
65+
if (root == null || root == p || root == q) return root;
66+
67+
TreeNode curr = root;
68+
while (curr != null) {
69+
if (curr.val > p.val && curr.val > q.val) { // 如果当前节点值同时大于 p、q 的值,说明 p、q 肯定都在左子树
70+
curr = curr.left;
71+
} else if (curr.val < p.val && curr.val < q.val) { // 如果当前节点值同时小于 p、q 的值,说明 p、q 肯定都在右子树
72+
curr = curr.right;
73+
} else {
74+
return curr;
75+
}
76+
}
77+
return curr;
78+
}
79+
80+
}
Lines changed: 34 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,56 @@
11
package io.github.dunwu.algorithm.tree.btree;
22

33
import io.github.dunwu.algorithm.tree.TreeUtils;
4-
import io.github.dunwu.algorithm.tree.btree.TreeNode;
4+
import org.junit.jupiter.api.Assertions;
55

66
/**
77
* <code>236. 二叉树的最近公共祖先</code> 算法实现
8-
* <p>
9-
* 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
10-
* <p>
11-
* 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
12-
* <p>
13-
* 例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4]
14-
* <p>
15-
* 示例 1:
16-
* <pre>
17-
* 输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
18-
* 输出: 3
19-
* 解释: 节点 5 和节点 1 的最近公共祖先是节点 3。
20-
* </pre>
21-
* 示例 2:
22-
* <pre>
23-
* 输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
24-
* 输出: 5
25-
* 解释: 节点 5 和节点 4 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身。
26-
* </pre>
27-
* 说明:
28-
* <pre>
29-
* 所有节点的值都是唯一的。
30-
* p、q 为不同节点且均存在于给定的二叉树中。
31-
* </pre>
328
*
339
* @see <a href="https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/">236. 二叉树的最近公共祖先</a>
10+
* @see <a href="https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/solution/er-cha-shu-de-zui-jin-gong-gong-zu-xian-by-leetc-2/">解题思路</a>
3411
*/
3512
public class 二叉树的最近公共祖先 {
3613

37-
private static TreeNode ans = null;
38-
3914
public static void main(String[] args) {
4015
TreeNode root = TreeUtils.buildTree(3, 5, 1, 6, 2, 0, 8, null, null, 7, 4);
41-
TreeNode p = new TreeNode(5);
42-
TreeNode q = new TreeNode(1);
16+
TreeNode p = TreeUtils.find(root, 5);
17+
TreeNode q = TreeUtils.find(root, 1);
4318
TreeNode treeNode = lowestCommonAncestor(root, p, q);
19+
Assertions.assertNotNull(treeNode);
20+
Assertions.assertEquals(3, treeNode.val);
4421
System.out.println("公共祖先节点 = " + treeNode.val);
22+
23+
TreeNode p2 = TreeUtils.find(root, 5);
24+
TreeNode q2 = TreeUtils.find(root, 4);
25+
TreeNode treeNode2 = lowestCommonAncestor(root, p2, q2);
26+
Assertions.assertNotNull(treeNode2);
27+
Assertions.assertEquals(5, treeNode2.val);
28+
System.out.println("公共祖先节点 = " + treeNode2.val);
4529
}
4630

31+
/**
32+
* 递归方式求解
33+
* <p>
34+
* 时间复杂度:O(N) 线性级
35+
* <p>
36+
* 空间复杂度:O(2) 常数级
37+
*/
4738
public static TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
48-
recurseTree(root, p, q);
49-
return ans;
50-
}
39+
// 如果当前节点为空,直接返回
40+
// 或当前节点就是 p 或 q 其中一个,显然就是要找的最近公共祖先,直接返回
41+
if (root == null || root == p || root == q) return root;
42+
43+
TreeNode left = lowestCommonAncestor(root.left, p, q);
44+
TreeNode right = lowestCommonAncestor(root.right, p, q);
5145

52-
private static boolean recurseTree(TreeNode root, TreeNode p, TreeNode q) {
53-
if (root == null) return false;
54-
boolean lson = recurseTree(root.left, p, q);
55-
boolean rson = recurseTree(root.right, p, q);
56-
boolean flag = (root.val == p.val || root.val == q.val) && (lson || rson);
57-
if ((lson && rson) || ((root.val == p.val || root.val == q.val) && (lson || rson))) { ans = root; }
58-
return (root.val == p.val || root.val == q.val) || (lson || rson);
46+
if (left == null) { // p、q 都不在左子树,查找右子树
47+
return right;
48+
} else if (right == null) { // p、q 都不在右子树,查找左子树
49+
return left;
50+
} else {
51+
// p、q 既不在左子树,又不在右子树,直接返回当前节点
52+
return root;
53+
}
5954
}
6055

6156
}

0 commit comments

Comments
 (0)