Live2D

模板整理

整理遇到的几个比较难记的算法的模板。

KMP算法

KMP算法是字符串匹配算法,通常是在长字符串中对短字符串(模式串)进行匹配。
使用next数组对模式串的前缀表进行记录。
前缀表:当匹配失败时,将根据这个前缀表决定指针的位置。前缀表的目的是找到模式串中相等的前缀和后缀。
例如aabaaf,对于i=1, 模式串为aa,前缀和后缀都是a,因此next中存储的是1。
这个过程类似自己跟自己匹配。 前缀部分的next是我们先得到的。因此在用后缀跟前缀匹配的时候,一旦匹配失败,我们可以得出,当前后缀的前缀跟前缀的前缀是相同的。
比如 abadxxxxabab,next=0 0 1 0 xxxx 1 2 3,当我们计算最后一个b的时候匹配失败了。
此时我们要找到能够匹配aba的后缀的整个字符串的前缀。我们已经知道aba后缀对应相等的前缀了。其实就是next[i-1],也就是当前的j=3.
那么这个值除了已经匹配失败的j=3,还有前缀aba对应的next,也满足这个要求。通过不断的往前进行搜索,得到结果。可以把这个过程看成一棵树。

在haystack中搜索模式串的原理和上面是差不多的。

class Solution {
    void getNext(int *next,string needle){
        int n=needle.size();
        int j=0;
        next[0] = j;
        for(int i=1;i<n;++i){
            while(j>0&&needle[j]!=needle[i]){
                j=next[j-1];
            }
            if(needle[j]==needle[i]){
                j++;
            }
            next[i]=j;
        }
    }
public:
    int strStr(string haystack, string needle) {
        int n=haystack.size(), m=needle.size();
        int next[m];
        getNext(next, needle);
        int i=0,j=0;
        for(int i=0;i<n;++i){
            while(j>0&&needle[j]!=haystack[i]){
                j=next[j-1];
            }
            if(haystack[i]==needle[j]){
                j++;
            }
            if(m==j){
                return (i - m + 1);
            }
        }
        return -1;
    }
};

在next查找的时候,我们需要使next[j-1]来查找对应的前缀。因此可以把next数组统一减一,相当于把数组右移了,因此访问的时候可以直接用next[j].但是很多地方就要改成j+1;
写法:

class Solution {
    void getNext(int *next,string needle){
        int n=needle.size();
        int j=-1;
        next[0] = j;
        for(int i=1;i<n;++i){
            while(j>=0&&needle[j+1]!=needle[i]){
                j=next[j];
            }
            if(needle[j+1]==needle[i]){
                j++;
            }
            next[i]=j;
        }
    }
public:
    int strStr(string haystack, string needle) {
        int n=haystack.size(), m=needle.size();
        int next[m];
        getNext(next, needle);
        int i=0,j=-1;
        for(int i=0;i<n;++i){
            while(j>=0&&needle[j+1]!=haystack[i]){
                j=next[j];
            }
            if(haystack[i]==needle[j+1]){
                j++;
            }
            if(m==j+1){
                return (i - m + 1);
            }
        }
        return -1;
    }
};

二叉树

二叉树的数据结构

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode() : val(0), left(nullptr), right(nullptr) {}
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};

二叉树常见的遍历:前序遍历(中左右)、中序遍历(左中右)、后序遍历(左右中)、层序遍历

递归遍历

用递归的方法遍历二叉树

前序遍历

class Solution {
public:
    void traversal(TreeNode* root, vector<int>& res){
        if(root==nullptr)return;
        res.push_back(root->val);
        traversal(root->left, res);
        traversal(root->right, res);
    }
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> res;
        traversal(root, res);
        return res;
    }
};

中序遍历

class Solution {
public:
    void traversal(TreeNode* root, vector<int>& res){
        if(root==nullptr)return;
        traversal(root->left, res);
        res.push_back(root->val);
        traversal(root->right, res);
    }
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int>res;
        traversal(root, res);
        return res;
    }
};

后序遍历

class Solution {
    void traversal(TreeNode* root, vector<int>& res){
        if(root==nullptr)return;
        traversal(root->left, res);
        traversal(root->right, res);
        res.push_back(root->val);
    }
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int>res;
        traversal(root, res);
        return res;
    }
};

迭代遍历

需要借助栈来保存。

前序遍历

使用栈来模拟整个过程.先把右指针进栈再进栈左指针,在出栈时取值

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        if(root==nullptr)return {};
        vector<int> res;
        stack<TreeNode*>nodes;
        
        nodes.push(root);
        while(!nodes.empty()){
            TreeNode* cur=nodes.top();
            nodes.pop();
            res.push_back(cur->val);
            if(cur->right != nullptr)nodes.push(cur->right);
            if(cur->left != nullptr)nodes.push(cur->left);
        }
        return res;
    }
};

或者,按照其一直往左走的特点实现在进栈时取值

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
      stack<TreeNode*> st;
        TreeNode* cur = root;
        vector<int> v;
        while(cur || !st.empty())
        {
            //开始访问一棵树
            //1,左路节点
            //2,左路节点的右子树
            while(cur)
            {
            v.push_back(cur->val);
            st.push(cur);
            cur=cur->left;
            }
            //开始访问右子树
            TreeNode* top = st.top();
            st.pop();
            //子问题访问右子树
            cur = top->right;
            }
            return v;
    }
};

中序遍历

只有节点的左子树都被访问过后,才将节点的值输出。

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        stack<TreeNode*>st;
        vector<int>res;
        TreeNode* cur=root;
        while(cur||!st.empty()){
            while(cur){
                st.push(cur);
                cur=cur->left;
            }
            TreeNode* node = st.top();
            st.pop();
            res.push_back(node->val);
            cur = node->right;
        }
        return res;
    }
};

后序遍历

左右中反过来就是中右左,因此把前序遍历的访问顺序翻转,再反过来就行了

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        vector<int> result;
        if (root == NULL) return result;
        st.push(root);
        while (!st.empty()) {
            TreeNode* node = st.top();
            st.pop();
            result.push_back(node->val);
            if (node->left) st.push(node->left); // 相对于前序遍历,这更改一下入栈顺序 (空节点不入栈)
            if (node->right) st.push(node->right); // 空节点不入栈
        }
        reverse(result.begin(), result.end()); // 将结果反转之后就是左右中的顺序了
        return result;
    }
};

统一的迭代法

在栈中加入NULL节点,表示上一个入栈的节点的左右节点是被访问过的。通过这种方法,可以把三种遍历统一起来。依旧是出栈的时候, 如果是NULL加入答案

前序遍历

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        TreeNode* cur = root;
        if(root!=nullptr)st.push(root);
        vector<int> res;
        while(!st.empty()){
            cur = st.top();
            st.pop();
            if(cur!=nullptr){
                if(cur->right)st.push(cur->right); //记得判断,否则会跟空节点混淆
                if(cur->left)st.push(cur->left);
                st.push(cur);
                st.push(nullptr);
            }else{
                cur = st.top();
                st.pop();
                res.push_back(cur->val);
            }
        }
        return res;
    }
};

中序遍历

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        TreeNode* cur = root;
        if(root!=nullptr)st.push(root);
        vector<int> res;
        while(!st.empty()){
            cur = st.top();
            st.pop();
            if(cur!=nullptr){
                if(cur->right)st.push(cur->right);
                
                st.push(cur);
                st.push(nullptr);

                if(cur->left)st.push(cur->left);
            }else{
                cur = st.top();
                st.pop();
                res.push_back(cur->val);
            }
        }
        return res;
    }
};

后序遍历

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        TreeNode* cur = root;
        if(root!=nullptr)st.push(root);
        vector<int> res;
        while(!st.empty()){
            cur = st.top();
            st.pop();
            if(cur!=nullptr){
                st.push(cur);
                st.push(nullptr);
                if(cur->right)st.push(cur->right);
                if(cur->left)st.push(cur->left);
            }else{
                cur = st.top();
                st.pop();
                res.push_back(cur->val);
            }
        }
        return res;
    }
};

层序遍历

迭代方法

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        queue<TreeNode*>q;
        if(root)q.push(root);
        vector<vector<int>> res;
        while(!q.empty()){
            int n=q.size();
            vector<int> layer;
            while(n--){
                TreeNode* tmp = q.front();
                q.pop();
                if(tmp->left) q.push(tmp->left);
                if(tmp->right) q.push(tmp->right);
                layer.push_back(tmp->val);
            }
            res.push_back(layer);
        }
        return res;
    }
};

递归方法

传入的res必须使用引用

class Solution {
public:
    void order(TreeNode* root, vector<vector<int>>& res, int depth){
        if(root == nullptr)return;
        if(depth+1>res.size()){
            res.push_back({});
        }
        res[depth].push_back(root->val);
        order(root->left, res, depth+1);
        order(root->right, res, depth+1);
    }
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> res;
        order(root, res, 0);
        return res;
    }
};

计算模板

有时候会遇到一些计算题。记录一些公式
等差数列 an+1 = an + d, an=a1+(n-1)d, S(n)=na1+n(n-1)d/2=(a1+an)n/2
等比数列 an = a1
q^(n-1), S(n) = a1(1-q^n)/(1-q)=(a1-anq)/(1-q);特殊情况:二叉树中,一般q=2, Sn=a1(q^n-1);

posted @ 2024-03-16 15:38  gamdwk  阅读(1)  评论(0编辑  收藏  举报
返回顶部