• 【左程云算法全讲2】链表、栈、队列、递归、哈希表和有序表


    系列综述:
    💞目的:本系列是个人整理为了秋招面试的,整理期间苛求每个知识点,平衡理解简易度与深入程度。
    🥰来源:材料主要源于左程云算法课程进行的,每个知识点的修正和深入主要参考各平台大佬的文章,其中也可能含有少量的个人实验自证。
    🤭结语:如果有帮到你的地方,就点个赞关注一下呗,谢谢🎈🎄🌷!!!
    🌈【C++】秋招&实习面经汇总篇



    😊点此到文末惊喜↩︎

    面试技巧

    1. 写算法时候也要阐述自己的思路,即使写不出来
    2. 面试的算法:必须找到最优的解

    链表

    1. 单向链表数据结构
      // 单链表数据结构
      struct LinkNode {
      	int val;
      	struct LinkNode *next;
      	LinkNode(int v): val(v), next(nullptr){}
      };
      // 反转单链表
      LinkNode *ReverseLinkList(LinkNode *head) {
      	LinkNode *prev = nullptr;
      	LinkNode *next = nullptr;
      	while (head != nullptr) {	// head充当cur指针,表示每个操作的结点
      		next = head->next;	// 记录值
      		head->next = prev;
      		prev = head;		// 两个指针的迭代
      		head = next;
      	}
      	return prev;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
    2. 双向链表数据结构
      • 使用双链表作为底层实现栈和队列
      struct LinkNode {
      	int val;
      	struct LinkNode *prev;
      	struct LinkNode *next;
      	LinkNode(int v): val(v), prev(nullptr), next(nullptr){}
      };
      // 反转双向链表
      LinkNode *ReverseLinkList(LinkNode *head) {
      	LinkNode *prev = nullptr;
      	LinkNode *next = nullptr;
      	while (head != nullptr) {	// head充当cur指针,表示每个操作的结点
      		next = head->next;		// 记录值
      		head->next = prev;		// key:当前双链表结点两个指针反转
      		head->prev = next;
      		prev = head;			// 两个指针的迭代
      		head = next;
      	}
      	return prev;
      }
      
      // 删除指定结点
      ListNode *DeleteTarget(ListNode *head, int target) {
          ListNode *vhead = new ListNode(-1);
          vhead->next = head;
      	
          ListNode *prev = vhead;
          ListNode *cur = head;
          while (cur != nullptr) {
              if (cur->val == target) {
                  ListNode *p = cur;
                  cur = cur->next;
                  delete p;		// 释放结点,jvm会自动释放
                  prev->next = cur;
              } else {
                  prev = cur;
                  cur = cur->next;
              }
          }
          return vhead->next;
      }
      设计一个模板双链表,可以进行头部和尾部的增删,以及改查操作,并进行优化
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41

    栈和队列

    1. 双链表实现栈和队列

    2. 数组实现栈和队列

      • 数组队列的实现应该是一个环状结构,使用
    3. 以O(1)时间获取当前栈的最小值

      • leetcode题目:最小栈
      • 思路1:最小栈同步记录对应的栈内最小值
      • 思路2:最小栈只记录栈内的最小值,只有当前栈和最小栈顶元素相等,最小栈栈顶才弹出
    class MinStack {
    public:
        /** initialize your data structure here. */
        MinStack() {
            min_st.push(INT_MAX);
        }
        
        void push(int x) {
            cur_st.push(x);
            int p = min_st.top();
            // 最小栈的栈顶一直记录栈内的最小值
            if (x <= p) {
                min_st.push(x);
            } else {
                min_st.push(p);
            }
        }
        
        void pop() {
            cur_st.pop();
            min_st.pop();
        }
        
        int top() {
            return cur_st.top();
        }
        
        int getMin() {
            return min_st.top();
        }
    private:
    	// 使用两个栈记录,一个记录当前栈,另一个栈顶一直为栈内最小元素
        stack<int> cur_st;	
        stack<int> min_st;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    1. 使用实现队列
      • 思路:两个栈,一个记录压入的元素,一个记录弹出的元素。
    class MyQueue {
    public:
        MyQueue() {
        }
        // 弹出栈为空则压入栈全部倒进弹出栈中
        void PushToPop(){
            if (pop_st.empty()) {
                while (!push_st.empty()) {
                    pop_st.push(push_st.top());
                    push_st.pop();
                }
            }
        }
        // 压入一个,则尝试倒栈
        void push(int x) {
            push_st.push(x);
            PushToPop();
        }
        // 先倒栈,在尝试弹出
        int pop() {
            PushToPop();
            int p = pop_st.top();
            pop_st.pop();
            return p;
        }
        int peek() {
            PushToPop();
            return pop_st.top();
        }
        bool empty() {
            return pop_st.empty() && push_st.empty();
        }
    private:
        stack<int> push_st;
        
        stack<int> pop_st;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    1. 使用队列实现
      • 思路:将队列头部的元素按序重新添加到队列尾部,其中最后一个即栈顶元素
    class MyStack {
    public:
        queue<int> que;
        /** Initialize your data structure here. */
        MyStack() { }
        /** Push element x onto stack. */
        void push(int x) {
            que.push(x);
        }
        /** Removes the element on top of the stack and returns that element. */
        int pop() {
            int size = que.size();
            size--;
            while (size--) { // 将队列头部的元素(除了最后一个元素外) 重新添加到队列尾部
                que.push(que.front());
                que.pop();
            }
            int result = que.front(); // 此时弹出的元素顺序就是栈的顺序了
            que.pop();
            return result;
        }
        // 队列的末尾元素即为栈顶元素
        int top() {
            return que.back();
        }
        /** Returns whether the stack is empty. */
        bool empty() {
            return que.empty();
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    递归

    1. 递归的固定参数可以使用全局或者引用,其中的可变参数作为参数
    2. 递归求数组的最大值
    int process(vector<int> &vec, int L, int R) {
        if (L == R) return vec[L];
        int mid = L + ((R-L)>>1);
        int left_max = process(vec, L, mid);
        int right_max = process(vec, mid+1, R);
        return max(left_max, right_max);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    1. 任何递归都可以改成非递归,因为递归本质利用了系统栈
    2. 特殊复杂度 T ( N ) = a ∗ T ( N / b ) + O ( N c ) T(N) = a*T(N/b) + O(N^c) T(N)=aT(N/b)+O(Nc),其中a、b和c都是常数,a是递归次数,b为递归划分分数,c
      • 如果 l o g b a < d log_ba < d logba<d,复杂度为 O ( N d ) O(N^d) O(Nd)
      • 如果 l o g b a > d log_ba > d logba>d,复杂度为 O ( N l o g b a ) O(N^{log_ba}) O(Nlogba)
      • 如果 l o g b a = d log_ba = d logba=d,复杂度为 O ( N d ∗ l o g N ) O(N^d * logN) O(NdlogN)


    少年,我观你骨骼清奇,颖悟绝伦,必成人中龙凤。
    不如点赞·收藏·关注一波

    🚩点此跳转到首行↩︎

    参考博客

    1. 对数器
    2. 单调队列
    3. 快速链表quicklist
    4. 《深入理解计算机系统》
    5. 侯捷C++全系列视频
    6. 待定引用
    7. 待定引用
    8. 待定引用
  • 相关阅读:
    idea创建同级项目-纠结是SB
    [golang 流媒体在线直播系统] 2.搭建基于golang的流媒体服务器实现拉流推流,以及Html客户端拉取hls类型的流
    ICC2:Design Planning(02)Shaping Placement
    常用I/O复用模型 --> 一、单线程Accept(无IO复用)
    Mac电脑BIM建模软件 Archicad 26 for Mac最新
    IMX6ULL学习笔记(2)——通过SD卡烧录镜像
    数据结构(c语言版本) 二叉树的遍历
    Ubuntu 18.04 安装 T265 相机驱动
    Python操作MySQL基础使用
    基于点标签的目标检测与计数深度学习框架盘点
  • 原文地址:https://blog.csdn.net/qq_43840665/article/details/134233999