update sort

This commit is contained in:
ranwenjie
2021-09-13 14:43:50 +08:00
parent d1ad2f3dbb
commit f72365e833
8 changed files with 169 additions and 65 deletions
+22
View File
@@ -22,6 +22,28 @@
* BM
## 滑动窗口
使用滑动窗口解决字符串问题,代码框架
```
int left = 0, right = 0;
while (right < s.size()) {
// 增大窗口
window.add(s[right]);
right++;
while (window needs shrink) {
// 缩小窗口
window.remove(s[left]);
left++;
}
}
```
## 参考
《Algorithms》
+4
View File
@@ -18,6 +18,10 @@
## [二叉查找树](2-二叉查找树/二叉查找树.md)
快速排序就是个二叉树的前序遍历,归并排序就是个二叉树的后序遍历
## [AVL树](3-平衡树AVL/README.md)
+28 -14
View File
@@ -18,7 +18,7 @@
* 桶排序
## 交换排序算法
# 交换排序算法
排序算法的复杂度由 `比较的次数` 和 `交换的次数` 一起决定。
@@ -77,14 +77,18 @@
递归一次,pivot 左边都比它小,右边都比它大。这是递归,分治的思想。
> 快速排序就是个二叉树的前序遍历,归并排序就是个二叉树的后序遍历
对 A[p...r] :
1. 分解:A[p..q-1] A[q+1..r],使得 A[p...q-1]<A[q]<A[q+1..r]
0. 选择最后一个元素作为 pivot (基准)
1. 分解:A[p..q-1] A[q+1..r],使得 A[p...q-1]< A[q] <A[q+1..r]
2. 解决:递归调用 快排,,对子数组A[p..q-1],A[q+1..r]排序
3. 合并(子问题相互独立的,因此用分治算法就可以了)
具体步骤:
1. 从数列中选择一个元素,作为基准 pivot。通常取分区的第一个或最后一个
1. 从数列中选择一个元素,作为基准 pivot。通常取分区的最后一个
2. 重排数列,比 pivot 小得排左边,比pivot大的排右边,相等的随便。 一句话就是`挖坑填数`
3. 递归的,使用相同的方式,重排左右两边的子序列
@@ -107,6 +111,7 @@
int i=start,j=end;
int tmp = a[i]; // 这里要做越界检查
while(i<j){
// 从后向前扫描,找到第一个小于tmp的值,来填a[i]
while(i<j && a[j]>=tmp){
j--;
@@ -115,6 +120,7 @@
{
a[i++] = a[j];
}
// 从左向右扫描,找一个大于 tmp的 数, 去填坑a[j]
while(i<j && a[i]<tmp){
i++;
@@ -124,6 +130,7 @@
a[j++]=a[i];
}
}
//扫描完成后,i==j
a[i]=tmp;
return i;
@@ -133,10 +140,9 @@
平均复杂度 O(n*logn)
最坏O(n^2)
平均复杂度 O(n * logn)
最坏 O(n^2)
空间复杂度
快速排序是对冒泡排序的改进,划分交换排序。
@@ -154,13 +160,21 @@
2. 解决。 将各个子数组都排好序,然后 merge 2个有序数组
3. 合并
if (length>1)
{
merge_sort(a,length/2);
merge_sort(a+length/2,length-length/2);
merge_array(a,length/2,a+length/2,length-length/2);
}
归并排序的代码框架如下:
```
void sort(int[] nums, int lo, int hi) {
int mid = (lo + hi) / 2;
sort(nums, lo, mid);
sort(nums, mid + 1, hi);
/****** 后序遍历位置 ******/
// 合并两个排好序的子数组
merge(nums, lo, mid, hi);
/************************/
}
```
@@ -239,7 +253,7 @@
国外也有人通过舞蹈的方式编排了几种基本的排序算法,非常有趣。[点这里去看看](http://v.youku.com/v_show/id_XMzMyODk4NTQ4.html?from=s1.8-1-1.2)
## 线性排序算法
# 线性排序算法
上面的算法都是基于比较的排序,时间复杂度最好也是 NlogN.而非基于比较的排序,可以突破NlogN的时间下限。当然,非比较的排序,也是需要有一些限定条件的。
@@ -252,7 +266,7 @@
### 小结
# 小结
常见的排序算法都是比较排序,比较排序的时间复杂度通常为 O(n^2) 或 O(nlogn)
但是如果带排序的数字有一些特俗性时,我们可以根据这来设计更加优化的排序算法。
@@ -123,6 +123,45 @@ int longest_continuious_number(const char *input,char *output){
```
## 最长无重复子串问题
给一个字符串,找出不包含有重复字符的最长子串的长度
如 ”abcabbcbb“ 输出 3
思路1: 两个指针
思路2: 窗口函数
两个指针窗口函数实现
```
int lengthOfLongestSubstring(string s) {
unordered_map<char, int> window;
int left = 0, right = 0;
int res = 0; // 记录结果
while (right < s.size()) {
char c = s[right];
right++;
// 进行窗口内数据的一系列更新
window[c]++;
// 判断左侧窗口是否要收缩
while (window[c] > 1) {
char d = s[left];
left++;
// 进行窗口内数据的一系列更新
window[d]--;
}
// 在这里更新答案
res = max(res, right - left);
}
return res;
}
```
## 求最大连续递增数字子串
如“ads3sl456789DF3456ld345AA”中的“456789”就是所求。这道题在上一道题目的基础上增加了数字要递增的条件。思路跟上面差不多,碰到不递增的数字就相当于第二个数字串了。
@@ -152,7 +191,6 @@ int longest_common_subsequence(const char *s1,const char *s2, char *common){
```
## 对称子字符串的最大长度
题目:输入一个字符串,输出该字符串中对称的子字符串的最大长度。比如输入字符串“google”,由于该字符串里最长的对称子字符串是“goog”,因此输出4。
@@ -2,8 +2,6 @@
## 翻转句子中单词的顺序
题目:输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。句子中单词以空格符隔开。为简单起见,标点符号和普通字母一样处理。
@@ -190,8 +188,6 @@ char *proc(char *str){
## 字符串原地压缩
题目描述:“abeeeeegaaaffa" 压缩为 "abe5ag3f2a",请编程实现。
@@ -24,7 +24,7 @@ B = [1,2,7]
A = [1,2,4,5,6,7]
```
思路1:
思路1:合并2个数列,变成 `[4,5,6,1,2,7]` , 归因排序即可
思路2:
+72 -43
View File
@@ -7,6 +7,9 @@
* 子树
写二叉树的算法题,都是基于递归框架的。我们先要搞清楚 root 节点它自己要做什么,然后根据题目要求选择使用前序,中序,后续的递归框架。
二元树的结点定义如下:
```
struct SBinaryTreeNode // a node of the binary tree
@@ -19,8 +22,56 @@ struct SBinaryTreeNode // a node of the binary tree
## 二叉树翻转
输入一颗二元查找树,将该树转换为它的镜像,即在转换后的二元查找树中,左子树的结点都大于右子树的结点。用递归和循环两种方法完成树的镜像转换。例
如输入:
```
8
/ \
6 10
/\ / \
5 7 9 11
```
输出:
```
8
/ \
10 6
/\ /\
11 9 7 5
```
思路:二叉树翻转 , 把二叉树上的每一个节点的左右子节点进行交换
```
// 将整棵树的节点翻转
TreeNode invertTree(TreeNode root) {
// base case
if (root == null) {
return null;
}
/**** 前序遍历位置 ****/
// root 节点需要交换它的左右子节点
TreeNode tmp = root.left;
root.left = root.right;
root.right = tmp;
// 让左右子节点继续翻转它们的子节点
invertTree(root.left);
invertTree(root.right);
return root;
}
```
## 把二元查找树转变成排序的双向链表
难度:中等
输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。要求`不能创建任何新的结点`,只调整指针的指向。
```
@@ -40,6 +91,27 @@ struct SBinaryTreeNode // a node of the binary tree
## 二叉树两个结点的最低共同父结点
设计一个算法,找出二叉树上任意两个结点的最近共同父结点。复杂度如果是O(n2)则不得分
输入二叉树中的两个结点,输出这两个结点在数中最低的共同父结点。
分析:求数中两个结点的最低共同结点是面试中经常出现的一个问题。这个问题至少有两个变种。
## 求一个二叉树中任意两个节点间的最大距离
两个节点的距离的定义是 这两个节点间边的个数,比如某个孩子节点和父节点间的距离是1,和相邻兄弟节点间的距离是2,优化时间空间复杂度。
## 在二元树中找出和为某一值的所有路径
题目:输入一个整数和一棵二元树。从树的根结点开始往下访问一直到叶结点所经过的所有结点形成一条路径。打印出和与输入整数相等的所有路径。
@@ -65,47 +137,4 @@ struct SBinaryTreeNode // a node of the binary tree
## 二叉树翻转
输入一颗二元查找树,将该树转换为它的镜像,即在转换后的二元查找树中,左子树的结点都大于右子树的结点。用递归和循环两种方法完成树的镜像转换。例
如输入:
```
8
/ \
6 10
/\ / \
5 7 9 11
```
输出:
```
8
/ \
10 6
/\ /\
11 9 7 5
```
## 二叉树两个结点的最低共同父结点
设计一个算法,找出二叉树上任意两个结点的最近共同父结点。复杂度如果是O(n2)则不得分
输入二叉树中的两个结点,输出这两个结点在数中最低的共同父结点。
分析:求数中两个结点的最低共同结点是面试中经常出现的一个问题。这个问题至少有两个变种。
## 求一个二叉树中任意两个节点间的最大距离
两个节点的距离的定义是 这两个节点间边的个数,比如某个孩子节点和父节点间的距离是1,和相邻兄弟节点间的距离是2,优化时间空间复杂度。
@@ -1,9 +1,10 @@
# 二叉树-遍历
> 快速排序就是个二叉树的前序遍历,归并排序就是个二叉树的后序遍历
## 俩种方法实现二叉树的前序遍历。
## 2种方法实现二叉树的前序遍历。
递归和非递归