一、算法快速复习(B站左神,最好是有基础的复习)
第一次学数据结构的时候看看这个视频该多好,转专业的娃一年学的东西太多,太费时间了。
1.算法的复杂度
2. 经典算法时间空间复杂度稳定性
时间、空间、稳定性三者问题
1.归并排序的额外空间复杂度可以变成0(1),但是非常难,不需要掌握,有兴趣可以搜“归并排序内部缓存法
2. “原地归并排序”的帖子都是垃圾,会让归并排序的时间复杂度变成0 (N-2)
3.快速排序可以做到稳定性问题,但是非常难,不需要掌握,可以搜"01stable sort"
4.所有的改进都不重要,因为目前没有找到时间复杂度0(N1ogN),额外空间复杂度0(1),又稳定的排序
5.有一道题目,是奇数放在数组左边,偶数放在数组右边,还要求原始的相对次序不变,碰到这个问题,可以01标准,理论级算法。
排序优化
与 o(N2 )与 o(NlogN)之间平衡,综合排序,大样本用NlogN,小样本N2
内部sort排序 采用算法为综合排序算法,复杂的排序策略
Hash表和有序表
c++ map、set表 unsortedmap : [key-> value]
时间复杂度 常数级别 增删改查
基础类型 | 按照值来传递,拷贝值 |
---|---|
自定义类型 | 按引用来传递,8字节内存地址 |
有序表的用法
1.内部根据Key 来组织结构,hash实现,有序表都可以实现,key可以比较,最小的键值,最大的键值,红黑树,AVL树、sb树、跳表都属于有序表结构,实现代价O(Nlogn)
2.自定义类型,需提供提交器来比较键值
链表结构
1.反转单向,双向链表(多个指针 pre cur next)
重要技巧
1. 额外数据结构
2. 快慢指针 不理解
回文链表: 借用栈,(全部,半个部分)
快慢指针: 考虑中点的边界条件
慢:每次一步
快: 每次两步
3步,长奇数偶数,
有限变量,不改原来结构,来回变相
没有空间限制:接触额外数据结构
**有空间限制:** 6个额外指针
小于头尾接点指针
等于头尾节点指针
大于头尾节点指针
!!!考虑边界情况
快门指针寻找入环头节点
设环外m,环内n节点,相遇时慢指针在环内走k步。此时慢走m+k步,快比慢多走m+k(快在绕圈圈等着慢),
结论(m+k)%n=0。快回起点走m到环入口,此时慢在环内走了k+m步%n=0,即在环入口相遇
树结构
递归 (先、中、后) 递归顺,每一层会有三次返回递归,此顺序为递归顺,选择顺序不同,可打印先中后三种顺序
^iod search(node){
//
if (n == null){ return}
//
search( node.left);;
//
search (node.right);
}
非递归
先序遍历:
1.压栈,节点入栈,cur
2.弹出一节点,处理
3. (存在节点),先压右孩子,在押左孩子
4.重复到无节点压入
后序遍历
再添加另外一个辅助栈, 先序遍历顺序情况下,将弹出的节点压入另外一个辅助栈
中序遍历
1.每棵树从头节点到树的左树先遍历
2.然后弹出左树,操作,如果左树有有有孩子节点,将有孩子压入
3.重复操作
广度优先遍历
队列 queue
返回最大的宽度:纪录每一节点的层数
思路:使用hashset纪录节点层数
使用层数最后一节点标记,同级同层节点个数。
二叉树的应用
- 判断是否为排序树 ,左小于根节点小于右
利用中序遍历 左 中 右 应该是从小到大递增的
1.使用 优先队列 ,将其入队, 使用临时变量来判断是否递增,用堆栈来解决 - 判断是否为满二叉树
(1)判断任一节点有右孩子无左孩子直接为否
(2)在1基础上第一次遇到有左右孩子不全情况下,接下来所有节点必须是叶节点
3.判断是否为满二叉树
(1) 二叉树的深度,然后判断节点数与深度的关系
(2) //思路不对 广度优先遍历,发现节点必须为左右孩子都在,或者发现左右孩子都不在的(后面在想)
// first define the return type, =>(leave,nodes_num)
class returnDate{
int leave,nodes_num;
bool tag;
returnDate(int leave,int nodes_num,bool tag){
this.leave = leave;
this.nodes_num = nodes_num;
this.tag =tag;
}
}
// 递归
returnDate isFull_tree(node x){
if(x==null) return (0,0,true);
returnDate nodeLeft = isFull_tree(x.left);
returnDate nodeRight = isFull_tree(x.right);
int nodes_nums, leave;
nodes_num= nodeLeft.nodes_num + nodeRight.nodes_num +1;
leave = nodeLeft.leave + 1;
if( nodeLeft.tag && nodeRight.tag && nodeLeft.leave==nodeRight.leave&&
nodeLeft.nodes_num = nodeRight.nodes_nums){
return nodes_num == 1>>leave -1 ? new returnDate(leave,nodes_num,ture) : new returndate(leave,nodes_num,false);
}
return new returnDate(leave,nodes_num,false) ;
}
4.判断是否为平衡二叉树
**基于左子树和右子树寻求信息,并且左右为平衡树并且左右子树只差不大于1**
递归学习构造 ,递归构造要一样!**如果对左右两树操作不一样,将左右树全局操作。**
class returnType{
int leave;
bool balanceT;
public:
returnType(int num, bool b){
this.leave = num;
this.balanceT = b;
}
}
returnType judeg_balacneT(node x){
if (x ==NUll) {
returnType a = new returnType(0,ture);
return a;
}
returnType nodeLeft = judge_balance(x.left);
returnType nodeRight = judge_balance(x.right);
int leave = max(nodeLeft.leave ,nodeRihgt.leave)+1;
bool isBalanced = nodeLeft.balanceT && nodeRight.balanceT && abs(nodeLeft.leave -nodeRight.leave)<2
returnType a = new returnType(leave,isblanced);
return a;
}
树形DP****基于左右树要信息,全集递归
- 给出两棵树节点 o1, o2, 求出第一个祖先节点
(1). 列出01所有祖先节点拍好队列,然后列出o2节点,判断是否在o1中
map<node,node> fatherMap;
father.insert(head,head)
hashmap(map fahterMap,node head){
if(head ==NULL) return;
fatherMap.insert(head.left,head);
fatherMap.insert(head.right,head);
hashMap(fatherMap, head.left);
hashMap(fatherMap,head>right);
}
Node LcommonAccent(Node head, Node o1, Node o2){
hashmap(fatherMap,head);
set<node> father_O1
node cur = o1;
while(cur!=fatherMap[cur]){
father_O1.insert(fatherMap[cur];
cur = fatherMap[cur];
}
father_O1.insert(head);
cur = o2;
while(cur!=fatherMap(cur){
if (father_O1.count(cur) >0) return cur;
cur = fatherMap(cur);
}
return head;
}
(2). 利用递归来解决,头节点分别向左右树索要有无o1、o2节点的踪迹
node LCommonAccent(node head, node o1, node o2){
if (head ==null || head ==o1 || head ==o2 ||) return head;
node left = LCommonAccent(head.leaf, o1,o2);
node right = LCommonAccent(head.right,o1,o2);
if( left !=NULL && right !=NULL) return head;
return left == NULL ? right : left;
}
- 最短路径寻找后继节点(中序遍历,asbd,b后继为d)
结构分析:
(1) x节点有右树,右树上最左的节点
(2)下节点无右树,往上追溯是不是父亲的左孩子,(查找某一子树最右节点)
(3)倘若为整棵树的最右节点,无后继节点
node Most_Left(node x){
while(x.left != NULL)
x = x.left;
return x;
}
node find_middleNext(node x)
{
if(x.right != NULL) return Most_Left(x);
node parent = x.parent;// r如果没有自己hashmap
while( parent != NULL && parent.left!= x){
x = parent;
parent = x.parent;
}
return parent;
}
- 二叉树的序列化和反序列化 // 将二叉树结构唯一化和暂存
#include <iostream>
#include <map>
#include <set>
#include <queue>
using namespace std;
struct node{
char value;
struct node * left=NULL;
struct node *right=NULL;
};
class Tree{
// private:
public:
node *head =NULL;
node *head_form=NULL;
// Tree(){};
Tree(char a){
node * n = new node;
*n = {a,NULL,NULL};
this->head = n ;
}
void init(node* head,char* s,int i){
queue<node*> nodes;
nodes.push(head);
while(!nodes.empty()){
node* head_tem = nodes.front();
nodes.pop();
node *a = new node;
node *b = new node;
if( s[i] != '\0'){
*a={s[i++],NULL,NULL};
head_tem->left = a;
nodes.push(head_tem->left);
}else
{
*a={'#',NULL,NULL};
head_tem->left = a;
}
if( s[i] != '\0'){
*b={s[i++],NULL,NULL};
head_tem->right = b;
nodes.push(head_tem->right);
}else
{
*b={'#',NULL,NULL};
head_tem->right = b;
}
}
} //put a RFL-tree-queue-to initiate the tree
void form_tree(char *s,int i){
if(s == NULL || s[i] =='\0' ) this->head_form =NULL;
else {
node *n = new node;
this->head_form = n;
RFL_queue_init(this->head_form,s,i);
}
}
void RFL_queue_init(node*& head_form, char* s,int &i){
if (s== NULL || s[i]== '\0') return;
if(s[i] == '#' ) {
i++;
return;
}
node *n = new node;
*n = {s[i++],NULL,NULL};
head_form = n;
RFL_queue_init(head_form->left, s,i);
RFL_queue_init(head_form->right,s,i);
}
void print(node *head){
if(head == NULL) return;
cout<< head->value;
print(head->left);
print(head->right);
}
};
int i= 0;
int main()
{
char s[] = "12345678";
Tree *a = new Tree('a');
int i = 0;
a->init(a->head,s,0);
a->print(a->head);
cout<<endl;
char tem[] ="a137##8##4##25##6##";
cout<<"the new tree";
a->form_tree(tem,i);
a->print(a->head_form);
// cout << (a->head)->value;
delete a;
return 0;
}
- 折纸折痕痕迹凸凹问题,一折为凸, 两者后凸凸凹,三者后凸凸凹凸凸凹凹(画成二叉树)
void ATprint(node *head,int i,bool flag){
if(i >2) return;
head = new node;
ATprint(head->left,i+1,true);
if(flag)
cout<<"Tu ";
else
cout<<"Ao ";
ATprint(head->right,i+1,false);
}