update dp

This commit is contained in:
ranwenjie
2021-11-14 22:42:14 +08:00
parent afc5b7ef2e
commit 4d67d29412
7 changed files with 161 additions and 26 deletions
+11 -3
View File
@@ -1,12 +1,15 @@
# 二叉查找树BST # 二叉查找树BST
二叉查找树(Binary search tree),也叫`有序二叉树(Ordered binary tree)`,`排序二叉树(Sorted binary tree)`。是指一个空树或者具有下列性质的二叉树: 二叉查找树(Binary search tree),也叫`有序二叉树(Ordered binary tree)`,`排序二叉树(Sorted binary tree)`。
是指一个空树或者具有下列性质的二叉树:
1. 若任意节点的左子树不为空,则左子树上所有的节点值小于它的根节点值 1. 若任意节点的左子树不为空,则左子树上所有的节点值小于它的根节点值
2. 若任意节点的右子树不为空,则右子树上所有节点的值均大于它的根节点的值 2. 若任意节点的右子树不为空,则右子树上所有节点的值均大于它的根节点的值
3. 任意节点左右子树也为二叉查找树 3. 任意节点左右子树也为二叉查找树
4. 没有键值(key)相等的节点 4. 没有键值(key)相等的节点
有序的二叉查找树,中序遍历结果是递增的。 有序的二叉查找树,中序遍历结果是递增的。
@@ -23,12 +26,15 @@
``` ```
### 删除节点
删除节点,需要重建排序树 删除节点,需要重建排序树
1) 删除节点是叶子节点(分支为0),结构不破坏 1) 删除节点是叶子节点(分支为0),结构不破坏
2)删除节点只有一个分支(分支为1),结构也不破坏 2)删除节点只有一个分支(分支为1),结构也不破坏
3)删除节点有2个分支,此时删除节点 3)删除节点有2个分支,此时删除节点 ; 需要重建树
思路一: 选左子树的最大节点,或右子树最小节点替换 思路一: 选左子树的最大节点,或右子树最小节点替换
``` ```
@@ -55,6 +61,7 @@ int bisearch_tree_delete(BiSearchTree **tree,ElemType node){
printf("树为空,或想要删除的节点不存在\n"); printf("树为空,或想要删除的节点不存在\n");
return -1; return -1;
} }
//该节点为叶子节点,直接删除 //该节点为叶子节点,直接删除
if (!target->rChild && !target->lChild) if (!target->rChild && !target->lChild)
{ {
@@ -86,7 +93,8 @@ int bisearch_tree_delete(BiSearchTree **tree,ElemType node){
target->rChild=target->rChild->rChild; target->rChild=target->rChild->rChild;
free(del); free(del);
} }
else{ //左右子树均不空,p,t 2个指针一前以后,将左子树最大的节点(肯定是一个最右的节点)替换到删除的节点后,还需要处理左子树最大节点的左子树 else{ //左右子树均不空,p,t 2个指针一前以后,将左子树最大的节点(肯定是一个最右的节点)替换到删除的节点后,还需要处理左子树最大节点的左子树
BiSearchTree *p=target,*t=target->lChild; BiSearchTree *p=target,*t=target->lChild;
+32 -11
View File
@@ -8,7 +8,7 @@ DP通常基于一个递推公式及一个(或多个)初始状态,当前子问
动态规划算法的关键在于解决冗余,以空间换时间的技术,需要存储过程中的各种状态。可以看着是`分治算法`+`解决冗余` 动态规划算法的关键在于解决冗余,以空间换时间的技术,需要存储过程中的各种状态。可以看着是`分治算法`+`解决冗余`
动态规划算法也可以说是 `记住求过的解来节省时间` 动态规划算法也可以说是 `记住求过的解来节省时间` ; 比如 Fibonacci数列 中,先直接从最小,最简单的 f(1) , f(2) 开始,自低向上一直到 f(20) , 这就是动态规划的思路
【初始状态】→【决策1】→【决策2】→…→【决策n】→【结束状态】 【初始状态】→【决策1】→【决策2】→…→【决策n】→【结束状态】
@@ -21,16 +21,20 @@ DP通常基于一个递推公式及一个(或多个)初始状态,当前子问
动态规划的核心思想就是穷举求最值; 动态规划问题的一般形式就是`求最值`,动态规划其实是运筹学的一种最优化方法,只不过在计算机问题上应用比较多,比如说: 动态规划的核心思想就是穷举求最值; 动态规划问题的一般形式就是`求最值`,动态规划其实是运筹学的一种最优化方法,只不过在计算机问题上应用比较多,比如说:
* 最长递增子序列 (LIS Longest Increasing Subsequence) * Fibonacci数列 [代码参考这里 递归](./递归.md)
* 最小编辑距离 * 凑零钱问题
* 0-1 背包问题 * 股票问题 [代码参考这里](https://github.com/nonstriater/deep-in-java/blob/master/src/main/java/com/nonstriater/deepinjava/algo/list/stock/BestChance.java)
* 凑零钱问题 * 二叉树的最近公共祖先 [代码参考这里](https://github.com/nonstriater/deep-in-java/blob/master/src/main/java/com/nonstriater/deepinjava/algo/tree/CommonParent.java)
* 股票问题 * 链表翻转 [代码参考这里](https://github.com/nonstriater/deep-in-java/blob/master/src/main/java/com/nonstriater/deepinjava/algo/link/ReverseLink.java)
* 接雨水问题 * 接雨水问题
* Fibonacci数列
* 青蛙跳阶问题: 一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 10 级的台阶总共有多少种跳法。 * 青蛙跳阶问题: 一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 10 级的台阶总共有多少种跳法。
* 二叉树的最近公共祖先 * 最小编辑距离
* 链表翻转 * 最长递增子序列 (LIS Longest Increasing Subsequence)
* 0-1 背包问题
[更多动态规划案例代码实现参考deep-in-java])(https://github.com/nonstriater/deep-in-java/tree/master/src/main/java/com/nonstriater/deepinjava/algo/framework/dynamic)
``` ```
@@ -69,7 +73,7 @@ DP 和 回溯法 都会用到递归
* 划分问题 * 划分问题
* 状态 * 状态
* 状态转移方程, 这一步最为困难 * 状态转移方程, 这一步最为困难 ; 暴力解法就是状态转移方程
* 状态压缩 * 状态压缩
@@ -87,6 +91,23 @@ for 状态1 in 状态1的所有取值:
## 凑零钱问题
凑零钱问题[视频解读参考这里]()
如果使用贪心策略,并不能得到最优解。
```Java
```
@@ -11,6 +11,19 @@
不需要考虑溢出。 不需要考虑溢出。
用例:
```
2^3 = 8
0^3 = 0
2^0 = 1
2^-3 = 1/(2^3) = 0.125
0^-3
```
分析:这是一道看起来很简单的问题。可能有不少的人在看到题目后30秒写出如下的代码: 分析:这是一道看起来很简单的问题。可能有不少的人在看到题目后30秒写出如下的代码:
``` ```
double Power(double base, int exponent) double Power(double base, int exponent)
@@ -35,15 +48,6 @@ double Power(double base, int exponent)
2^1 = 2 2^1 = 2
``` ```
用例:
```
2 3 = 8
0 3 = 0
2 0 = 1
2 -3 = 1/(2^3) = 0.125
0 -3
```
使用递归实现的代码示例: 使用递归实现的代码示例:
@@ -62,6 +66,25 @@ double Power(double base, unsigned int exponent)
``` ```
## Sqrt(x)
给你一个非负整数 x ,计算并返回 x 的 算术平方根 。由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。
示例 1:
```
输入:x = 4
输出:2
```
示例 2:
```
输入:x = 8
输出:2
解释:8 的算术平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。
```
## 求根号2的值 ## 求根号2的值
并且按照我的需要列出指定小数位,比如根号2是1.141 我要列出1位小数就是1.1 2位就是1.14, 1000位就是1.141...... 等。。 并且按照我的需要列出指定小数位,比如根号2是1.141 我要列出1位小数就是1.1 2位就是1.14, 1000位就是1.141...... 等。。
@@ -141,4 +141,35 @@ int one_appear_count(int n);
## 搜索旋转排序数组
整数数组 nums 按升序排列,数组中的值 互不相同 。
在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。
给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。
示例 1:
```
输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4
```
示例 2:
```
输入:nums = [4,5,6,7,0,1,2], target = 3
输出:-1
```
+4 -2
View File
@@ -107,8 +107,7 @@ TreeNode invertTree(TreeNode root) {
## 二叉树两个结点的最低共同父结点 (最近公共祖先)
## 二叉树两个结点的最低共同父结点
设计一个算法,找出二叉树上任意两个结点的最近共同父结点。复杂度如果是O(n2)则不得分 设计一个算法,找出二叉树上任意两个结点的最近共同父结点。复杂度如果是O(n2)则不得分
@@ -119,6 +118,9 @@ TreeNode invertTree(TreeNode root) {
## 求一个二叉树中任意两个节点间的最大距离 ## 求一个二叉树中任意两个节点间的最大距离
两个节点的距离的定义是 这两个节点间边的个数,比如某个孩子节点和父节点间的距离是1,和相邻兄弟节点间的距离是2,优化时间空间复杂度。 两个节点的距离的定义是 这两个节点间边的个数,比如某个孩子节点和父节点间的距离是1,和相邻兄弟节点间的距离是2,优化时间空间复杂度。
@@ -49,13 +49,30 @@
分析:这道题本质上还是考查二元树的遍历。对于一颗完全二叉树,要求给所有节点加上一个pNext指针,指向同一层的相邻节点;如果当前节点已经是该层的最后一个节点,则将pNext指针指向NULL;给出程序实现,并分析时间复杂度和空间复杂度。 分析:这道题本质上还是考查二元树的遍历。对于一颗完全二叉树,要求给所有节点加上一个pNext指针,指向同一层的相邻节点;如果当前节点已经是该层的最后一个节点,则将pNext指针指向NULL;给出程序实现,并分析时间复杂度和空间复杂度。
## 二元树的最小深度
例如:输入二元树:
```
10
/ \
6 14
/ \
12 16
```
输出该树的最小深度2。
## 判断整数序列是不是二元查找树的后序遍历结果 ## 判断整数序列是不是二元查找树的后序遍历结果
题目:输入一个整数数组,判断该数组是不是某二元查找树的后序遍历的结果。 题目:输入一个整数数组,判断该数组是不是某二元查找树的后序遍历的结果。
如果是返回true,否则返回false。 如果是返回true,否则返回false。
例如输入5、7、6、9、11、10、8,由于这一整数序列是如下树的后序遍历结果:
例如输入`5、7、6、9、11、10、8`,由于这一整数序列是如下树的后序遍历结果:
``` ```
8 8
/ \ / \
@@ -66,3 +83,9 @@
因此返回true。如果输入7、4、6、5,没有哪棵树的后序遍历的结果是这个序列,因此返回false。 因此返回true。如果输入7、4、6、5,没有哪棵树的后序遍历的结果是这个序列,因此返回false。
@@ -0,0 +1,27 @@
# 二叉搜索树
关于二叉查找树特性[参考这里](../4%20Tree/2-二叉查找树/二叉查找树.md)
## 验证二叉搜索树
## 二叉搜索树中的节点搜索
## 二叉搜索树中的插入操作
## 删除二叉搜索树中的节点