算法入门到放弃

一、算法快速复习(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)判断任一节点有右孩子无左孩子直接为否
    (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 + 1if( 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****基于左右树要信息,全集递归

  1. 给出两棵树节点 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;
}
  1. 最短路径寻找后继节点(中序遍历,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;
}
  1. 二叉树的序列化和反序列化 // 将二叉树结构唯一化和暂存
#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;

}
  1. 折纸折痕痕迹凸凹问题,一折为凸, 两者后凸凸凹,三者后凸凸凹凸凸凹凹(画成二叉树)
       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);
       }

猜你喜欢

转载自blog.csdn.net/huangdxian/article/details/121244573