常见算法总结

二叉树遍历

void inorder(TreeNode* root, vector<int>& ans) {
        if(!root) return;
        inorder(root->left, ans);
        ans.push_back(root->val);//处理root节点,可换为其他代码
        inorder(root->right, ans);
    }
    
void preorder(TreeNode* root, vector<int>& ans) {
        if(!root) return;
        ans.push_back(root->val);//处理root节点,可换为其他代码
        preorder(root->left, ans);
        preorder(root->right, ans);
    }
    
void postorder(TreeNode* root, vector<int>& ans) {
        if(!root) return;
        postorder(root->left, ans);
        postorder(root->right, ans);
        ans.push_back(root->val);//处理root节点,可换为其他代码
    }

//level traversal
vector<vector<int>> levelorder(TreeNode* root, vector<int>& ans){
		if(!root)	return {};
		vector<vector<int>> res;
		queue<TreeNode*> q = {{root}};
		while(!q.empty()){
			vector<int> level;
			for(int i=q.size(); i > 0; --i){
				TreeNode* temp = q.front();
				q.pop();
				level.push_back(temp->val);
				if(temp->left)	q.push_back(temp->left);
				if(temp->right)	q.push_back(temp->right);
			}
			res.push_back(level);
		}
		return res;	
}

    

并查集

并查集使用一种树形的数据结构,处理例如:两个人是否认识,两个地点能否通过一些路径连通,等抽象为连通性的问题。
核心API:union, find, connected
注:并查集只能回答连通与否,并不能找到连通路径。

典型题目:力扣323, 399. 除法求值
典型应用:

  • 检查图中是否有环(将边进行合并,在合并之前判断是否已经连通,如果在合并之前就已经连通则说明图中存在环)
  • c++代码
//带路径压缩的代码模板
class UnionFind{
    vector<int> parent;
    vector<int> size;
    int n;
    int part;
    
    UnionFind(int n){
        this->n = n;
        part = n;
        parent.resize(n);
        size.resize(n,1);
        for(int x=0; x<n; x++){
            parent[x] = x;
        }
    }
    //利用递归实现,每次查找之后都对find过程进行了路径的压缩
    int find(int x){
        if(x != parent[x]){
            parent[x] = find(parent[x]);
            return parent[x];
        }
        return x;
    }
    
    bool connected(int x, int y){
        return find(x) == find(y);
    }
    
    void Union_part(int x, int y){
        //给定两个点,将两个点所在的根连起来(小的放到大的里面去)
        int root_x = find(x);
        int root_y = find(y);
        if(root_x == root_y)	return;
        if(size[root_x] >= size[root_y]){
            parent[root_y] = root_x;
            size[root_x] += size[root_y];
            part -= 1;
        }
        else{
            parent[root_x] = root_y;
            size[root_y] += size[root_x];
            part -= 1;
        }
    }
    
    int get_part_size(int x){
        int root = find(x);
        return size[root];
    }
};
  • python代码
//带有路径压缩的代码模板
class UF:
    def __init__(self, M):
        self.parent = {}
        self.size = {}
        self.cnt = 0
        # 初始化 parent,size 和 cnt
        for i in range(M):
            self.parent[i] = i
            self.cnt += 1
            self.size[i] = 1

    def find(self, x):
        if x != self.parent[x]:
            self.parent[x] = self.find(self.parent[x])
            return self.parent[x]
        return x
    def union(self, p, q):
        if self.connected(p, q): return
        # 小的树挂到大的树上, 使树尽量平衡
        leader_p = self.find(p)
        leader_q = self.find(q)
        if self.size[leader_p] < self.size[leader_q]:
            self.parent[leader_p] = leader_q
            self.size[leader_q] += self.size[leader_p]
        else:
            self.parent[leader_q] = leader_p
            self.size[leader_p] += self.size[leader_q]
        self.cnt -= 1
    def connected(self, p, q):
        return self.find(p) == self.find(q)

我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:

  1. 全新的界面设计 ,将会带来全新的写作体验;
  2. 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
  3. 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
  4. 全新的 KaTeX数学公式 语法;
  5. 增加了支持甘特图的mermaid语法1 功能;
  6. 增加了 多屏幕编辑 Markdown文章功能;
  7. 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
  8. 增加了 检查列表 功能。

DFS

从root节点开始,尽可能的搜索每一个分支(一个分支搜完搜下一个)
典型题目:走迷宫

void dfs(int step)
{
        判断边界
        {
            相应操作
        }
        尝试每一种可能
        {
               满足check条件
               标记
               继续下一步dfs(step+1)
               恢复初始状态(回溯的时候要用到)
        }
} 

撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
检查列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G
查找:Ctrl/Command + F
替换:Ctrl/Command + G

二分法

  1. [l, r)
def binary_search(l, r):
    while l < r:
        m = l + (r - l) // 2
        if f(m): return m # optioncal
        if g(m) 
            r = m
        else
            l = m + 1
    return l # 最小的,满足 g(m)条件的索引
  1. [l, r]
def binary_search(l, r):
    while l <= r:
        m = l + (r - l) // 2
        if f(m): return m # optioncal
        if g(m) 
            r = m - 1
        else
            l = m + 1
    return l # 最小的,满足 g(m)条件的索引
  1. 有序数列,数字出现次数不唯一
int find(vector<int>& nums, int begin, int end, int k){
    while(begin < end){
        int mid = (begin + end)/2;
        if(nums[mid]>=k){
            end = mid;
        }
        else{
            begin = mid+1;
        }
    }
    if(begin == end && nums[begin]!=k)  return -1;
    return begin;
}

直接输入1次#,并按下space后,将生成1级标题。
输入2次#,并按下space后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用TOC语法后生成一个完美的目录。

背包问题(动态规划)

具体可参见《背包九讲》

0-1背包

N件物品,容量为V的背包,c[i]表示费用,w[i]表示重量,总重量不超且总价值最大。每个物品仅有一件,可以选择放/不放

  1. 恰好装满
    初始化:dp[0][0]=0, dp[0][j]=INT_MIN
    状态:f[i][j]表示容量为j,放前i件物品的最大价值。
    状态转移:f[i][j] = max(f[i-1][j],f[i-1][j-c[i]]+w[i])
    结果:f[N][0…V]的最大值

  2. 只要小于就可以
    初始化:if j>c[0], f[0][j] = w[0]
    状态:f[i][j]表示容量为j,放前i件物品的最大价值。
    状态转移:f[i][j] = max(f[i-1][j],f[i-1][j-c[i]]+w[i])
    结果:f[N][0…V]的最大值

// 初始化时倒叙遍历
for (int j = bagWeight; j >= weight[0]; j--) {
    dp[0][j] = dp[0][j - weight[0]] + value[0]; // 初始化i为0时候的情况
}

0-1背包,背包容量要从大到小遍历

// 核心代码
for(int i = 0; i < weight.size(); i++) { // 遍历物品
    for(int j = bagWeight; j >= weight[i]; j--) { // 遍历背包容量
        dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
    }
}

完全背包

每个物品无限件可用
状态:f[i][j]表示容量为j,放前i件物品的最大价值。
状态转移:f[i][j] = max(f[i-1][j],f[i-1][j-c[i]]+w[i])
结果:f[N][0…V]的最大值

完全背包,背包容量可以从小到大遍历

// 先遍历物品,再遍历背包
for(int i = 0; i < weight.size(); i++) { // 遍历物品
    for(int j = weight[i]; j < bagWeight ; j++) { // 遍历背包容量
        dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);

    }
}

多重背包

第i件物品最多有Mi件可用
将有多件的物品拆成Mi个,题目变为0-1背包问题。

// 多件的物品拆成Mi个
for (int i = 0; i < nums.size(); i++) {
        while (nums[i] > 1) { // nums[i]保留到1,把其他物品都展开
            weight.push_back(weight[i]);
            value.push_back(value[i]);
            nums[i]--;
        }
    }
// 核心代码
for(int i = 0; i < weight.size(); i++) { // 遍历物品
        for(int j = bagWeight; j >= weight[i]; j--) { // 遍历背包容量
            dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
        }
    }

  1. mermaid语法说明 ↩︎

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值