美文网首页
常用算法模板

常用算法模板

作者: 听松客未眠 | 来源:发表于2020-07-24 10:26 被阅读0次

动态规划(记忆化搜索)

给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。

from functools import lru_cache
import sys

class Solution:
    def minPathSum(self, grid: List[List[int]]) -> int:
        m, n = len(grid), len(grid[0])

        @lru_cache(None)
        def dfs(i, j):
            if i == m - 1 and j == n - 1:
                return grid[i][j]

            if i == m or j == n:
                return sys.maxsize

            rst = min(dfs(i + 1, j) + grid[i][j], dfs(i, j + 1) + grid[i][j])
            return rst

        return dfs(0, 0)

栈与队列

单调栈

leetcode 739
请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。

可以维护一个存储下标的单调栈,从栈底到栈顶的下标对应的温度列表中的温度依次递减。如果一个下标在单调栈里,则表示尚未找到下一次温度更高的下标。

class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& T) {
        stack<int> s;
        vector<int> ret(T.size(), 0);
        
        for (int i = T.size() - 1; i >= 0; --i) {
            while (s.size() > 0 && T[s.top()] <= T[i]) {
                s.pop();
            }
            
            if (s.size() > 0) {
                ret[i] = s.top() - i;
            }
            
            s.push(i);
        }
        
        return ret;
    }
};

判断括号

leetcode 20

class Solution {
public:
    bool isValid(string s) {
        stack<char> st;
        
        for (char c: s) {
            if (c == '(' || c == '[' || c == '{') {
                st.push(c);
            }
            else if (c == ')') {
                if (!st.empty() && st.top() == '(') {
                    st.pop();
                }
                else {
                    return false;
                }
            }
            else if (c == ']') {
                if (!st.empty() && st.top() == '[') {
                    st.pop();
                }
                else {
                    return false;
                }
            }
            else if (c == '}') {
                if (!st.empty() && st.top() == '{') {
                    st.pop();
                }
                else {
                    return false;
                }
            }
        }
        
        return st.empty();
    }
};

树的遍历

使用队列的BFS

/**
 * Return the length of the shortest path between root and target node.
 */
int BFS(Node root, Node target) {
    Queue<Node> queue;  // store all nodes which are waiting to be processed
    int step = 0;       // number of steps neeeded from root to current node
    // initialize
    add root to queue;
    // BFS
    while (queue is not empty) {
        step = step + 1;
        // iterate the nodes which are already in the queue
        int size = queue.size();
        for (int i = 0; i < size; ++i) {
            Node cur = the first node in queue;
            return step if cur is target;
            for (Node next : the neighbors of cur) {
                add next to queue;
            }
            remove the first node from queue;
        }
    }
    return -1;          // there is no path from root to target
}

使用栈的DFS

/*
 * Return true if there is a path from cur to target.
 */
boolean DFS(int root, int target) {
    Set<Node> visited;
    Stack<Node> s;
    add root to s;
    while (s is not empty) {
        Node cur = the top element in s;
        return true if cur is target;
        for (Node next : the neighbors of cur) {
            if (next is not in visited) {
                add next to s;
                add next to visited;
            }
        }
        remove cur from s;
    }
    return false;
}

二叉树的后序遍历

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        stack<tuple<TreeNode*, bool>> s;
        
        vector<int> ret;
        
        auto n = root;
        bool flag = false;
        
        while (!s.empty() || n) {            
            while (n) {
                s.push(make_tuple(n, false));
                n = n->left;
            }
            
            tie(n, flag) = s.top();
            s.pop();
            
            if (!flag) {
                s.push(make_tuple(n, true));
                n = n->right;
            }
            else {
                ret.emplace_back(n->val);
                n = nullptr;
            }
        }
        
        return ret;
    }
};

从前序与中序遍历序列构造二叉树

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        int n = preorder.size();
        
        if (n == 0) {
            return nullptr;
        }
        
        return func(preorder, inorder, 0, n - 1, 0, n - 1);
    }
private:
    TreeNode* func(vector<int>& preorder, vector<int>& inorder, int pStart, int pEnd, int iStart, int iEnd) {
        if (iEnd < iStart) {
            return nullptr;
        }
        
        auto n = new TreeNode(preorder[pStart]);
        
        int sp = iStart;
        while (sp < iEnd && inorder[sp] != n->val) {
            ++sp;
        }
        
        n->left = func(preorder, inorder, pStart + 1, sp - iStart + pStart, iStart, sp - 1);
        n->right = func(preorder, inorder, sp - iStart + pStart + 1, pEnd, sp + 1, iEnd);
        
        return n;
    }
};

二叉树层序序列化和反序列化

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Codec {
public:

    // Encodes a tree to a single string.
    string serialize(TreeNode* root) {
        if (root == nullptr) {
            return "[]";
        }
        
        queue<TreeNode*> q;
        
        q.push(root);
        
        vector<string> rst;
        
        while (!q.empty()) {
            TreeNode* n = q.front();
            q.pop();
            
            if (n) {
                rst.emplace_back(to_string(n->val));
                q.push(n->left);
                q.push(n->right);
            }
            else {
                rst.emplace_back("null");
            }
            
        }
        
        auto end = rst.end() - 1;
        
        while (*end == "null") {
            --end;
        }
        
        string s = "[";
        
        for (auto it = rst.begin(); it <= end; ++it) {
            if (s.size() > 1) {
                s.push_back(',');
            }
            
            s.append(*it);
        }
        
        s.push_back(']');
        
        return s;
    }

    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
        vector<string> d;
        
        int p = 1, q = 1, n = data.size();
        
        if (n < 3) {
            return nullptr;
        }
        
        while (q < n) {
            while (q < n - 1 && data[q] != ',') {
                ++q;
            }
            
            d.emplace_back(data.substr(p, q - p));
            p = q + 1;
            q = p;
        }
        
        int m = d.size();
        
        if (d[0] == "null") {
            return nullptr;
        }
        
        TreeNode* root = new TreeNode(stoi(d[0], nullptr));
        queue<TreeNode*> qu;
        qu.push(root);
        
        int i = 1;
        while (i < m) {
            auto n = qu.front();
            qu.pop();
            
            if (d[i] != "null") {
                auto nn = new TreeNode(stoi(d[i], nullptr));
                
                n->left = nn;
                
                qu.push(nn);
            }
        
            ++i;
            if (i == m) {
                break;
            }
            
            if (d[i] != "null") {
                auto nn = new TreeNode(stoi(d[i], nullptr));
                
                n->right = nn;
                
                qu.push(nn);
            }
            ++i;
        }
        
        return root;
    }
};

// Your Codec object will be instantiated and called as such:
// Codec codec;
// codec.deserialize(codec.serialize(root));

dijkstra算法

from collections import defaultdict
from heapq import *

heap = [(0, V)]
dists = {}

while len(heap) > 0:
    d, v = heappop(heap)

    if v in dists:
        continue

    dists[v] = d
    
    if v == target:
        break

    for vv, c in rels[v].items():
        heappush(heap, (d + c, vv))

floyd算法


import numpy as np
 
N = 4
M = 100
edge = np.mat([[0,2,6,4],[M,0,3,M],[7,M,0,1],[5,M,12,0]])
A = edge[:]
path = np.zeros((N,N))
 
def Floyd():
    for i in range(N):
        for j in range(N):
            if(edge[i,j] != M and edge[i,j] != 0):
                path[i][j] = i
 
    print 'init:'
    print A,'\n',path
    for a in range(N):
        for b in range(N):
            for c in range(N):
                if(A[b,a]+A[a,c]<A[b,c]):
                    A[b,c] = A[b,a] + A[a,c]
                    path[b][c] = path[a][c]
 
    print 'result:'
    print A,'\n',path

————————————————
版权声明:本文为CSDN博主「撕书」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Lwenjiyou_/java/article/details/79548577

拓扑排序

from collections import defaultdict

inds = defaultdict(int)

for v, e in graph.items():
    for vv in e:
        inds[vv] += 1

for v in nodes:
    if inds[v] == 0:
        q.append(v)

rst = []
while len(q) > 0:
    v = q.popleft()
    rst.append(v)

    for vv in graph[v]:
        inds[vv] -= 1

        if inds[vv] == 0:
            q.append(vv)

最小生成树 Prim

import heapq
vs = {V}
q = {}

for v, c in edges[V].items():
    heapq.heappush(q, (c, v))

while len(vs) < N:
    cost, v  = heapq.heappop(q)

    if v in vs:
        continue

    vs.add(v)

    for vv, c in edges[v].items():
        if vv not in vs:
            heapq.heappush(q, (c, vv))

最大流

SAP 算法

int gap[maxN]; //层次网络中某一层包含节点的个数
int map[maxN][maxN];//邻接矩阵
int level[maxN]; //层次
int pre[maxN]; //增广路中节点的前一个节点

//m为节点总个数
int sap(int m)
{
    //一开始所有节点的层次设为0
    int result = 0;
    gap[0] = m;
    pre[1] = 1;
    int u = 1 , v;
    while (level[1] < m)
    {
        //找可行弧
        for (v = 1; v <= m; v++)
        {
            if (map[u][v] && level[u] == level[v] + 1) break;
        }
        //找到了可行弧
        if (v <= m)
        {
            pre[v] = u;
            u = v;
            //找到了一条增广路,做流量调整
            if (v == m)
            {
                int min = 1e8;
                for (int i = v; i != 1; i = pre[i])
                    if (min > map[pre[i]][i])
                        min = map[pre[i]][i];
                result += min;
                for (int i = v; i != 1; i = pre[i])
                {
                    map[pre[i]][i] -= min;
                    map[i][pre[i]] += min;
                }
                u = 1;
            }
        }
        else {
            //未找到可行弧,调节层次网络,将当前节点的层次设为周围所有节点层次最小值+1,
            //以确保下一次能找到可行弧
            int minlevel = 1e5;
            for (int i = 1; i <= m; i++)
                if (map[u][i] && minlevel > level[i])
                    minlevel = level[i];
            //gap优化 如果当前这个节点的层次中只包含这个节点,在这个节点的层次做调整后,
            //当前网络就不再包含具有这个层次的节点了,这个时候是一定没办法找到可行流的,
            //因此算法可以终止了。
            gap[level[u]]--;
            if (gap[level[u]] == 0) break;
            level[u] = minlevel + 1;
            gap[minlevel + 1]++;
            u = pre[u];
        }
    }
    return result;
}
原文链接:https://blog.csdn.net/yjr3426619/java/article/details/82808303

欧拉路径

leetcode 332
给定一个机票的字符串二维数组 [from, to],子数组中的两个成员分别表示飞机出发和降落的机场地点,对该行程进行重新规划排序。所有这些机票都属于一个从JFK(肯尼迪国际机场)出发的先生,所以该行程必须从 JFK 出发

from collections import defaultdict, deque

class Solution:
    def findItinerary(self, tickets: List[List[str]]) -> List[str]:
        edges = defaultdict(dict)

        for a, b in tickets:
            edges[a][b] = edges[a].get(b, 0) + 1

        rst = []

        def go(v):
            for vv in sorted(list(edges[v])):
                if edges[v][vv] > 0:
                    edges[v][vv] -= 1
                    go(vv)

            rst.append(v)

        go('JFK')

        rst.reverse()

        return rst

二分图

class Solution {
public:
    bool isBipartite(vector<vector<int>>& graph) {
        vector<int> colors(graph.size(), 0);

        for (int i = 0; i < colors.size(); ++i) {
            if (colors[i] == 0) {
                if (!dfs(graph, i, 1, colors)) {
                    return false;
                }
            }
        }

        return true;
    }
private:
    bool dfs(vector<vector<int>>& graph, int v, int color, vector<int>& colors) {
        if (colors[v] != 0) {
            return color == colors[v];
        }

        colors[v] = color;

        for (int i = 0; i < graph[v].size(); ++i) {
            int colorTo = color == 1 ? 2 : 1;
            if (!dfs(graph, graph[v][i], colorTo, colors)) {
                return false;
            }
        }

        return true;
    }
};

匈牙利算法

https://zhuanlan.zhihu.com/p/96229700

int M, N;            //M, N分别表示左、右侧集合的元素数量
int Map[MAXM][MAXN]; //邻接矩阵存图
int p[MAXN];         //记录当前右侧元素所对应的左侧元素
bool vis[MAXN];      //记录右侧元素是否已被访问过
bool match(int i)
{
    for (int j = 1; j <= N; ++j)
        if (Map[i][j] && !vis[j]) //有边且未访问
        {
            vis[j] = true;                 //记录状态为访问过
            if (p[j] == 0 || match(p[j])) //如果暂无匹配,或者原来匹配的左侧元素可以找到新的匹配
            {
                p[j] = i;    //当前左侧元素成为当前右侧元素的新匹配
                return true; //返回匹配成功
            }
        }
    return false; //循环结束,仍未找到匹配,返回匹配失败
}
int Hungarian()
{
    int cnt = 0;
    for (int i = 1; i <= M; ++i)
    {
        memset(vis, 0, sizeof(vis)); //重置vis数组
        if (match(i))
            cnt++;
    }
    return cnt;
}

km算法

https://www.jianshu.com/p/c59ab6a5dbf8

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>

using namespace std;
const int MAXN = 305;
const int INF = 0x3f3f3f3f;

int love[MAXN][MAXN];   // 记录每个妹子和每个男生的好感度
int ex_girl[MAXN];      // 每个妹子的期望值
int ex_boy[MAXN];       // 每个男生的期望值
bool vis_girl[MAXN];    // 记录每一轮匹配匹配过的女生
bool vis_boy[MAXN];     // 记录每一轮匹配匹配过的男生
int match[MAXN];        // 记录每个男生匹配到的妹子 如果没有则为-1
int slack[MAXN];        // 记录每个汉子如果能被妹子倾心最少还需要多少期望值

int N;


bool dfs(int girl)
{
    vis_girl[girl] = true;

    for (int boy = 0; boy < N; ++boy) {

        if (vis_boy[boy]) continue; // 每一轮匹配 每个男生只尝试一次

        int gap = ex_girl[girl] + ex_boy[boy] - love[girl][boy];

        if (gap == 0) {  // 如果符合要求
            vis_boy[boy] = true;
            if (match[boy] == -1 || dfs( match[boy] )) {    // 找到一个没有匹配的男生 或者该男生的妹子可以找到其他人
                match[boy] = girl;
                return true;
            }
        } else {
            slack[boy] = min(slack[boy], gap);  // slack 可以理解为该男生要得到女生的倾心 还需多少期望值 取最小值 备胎的样子【捂脸
        }
    }

    return false;
}

int KM()
{
    memset(match, -1, sizeof match);    // 初始每个男生都没有匹配的女生
    memset(ex_boy, 0, sizeof ex_boy);   // 初始每个男生的期望值为0

    // 每个女生的初始期望值是与她相连的男生最大的好感度
    for (int i = 0; i < N; ++i) {
        ex_girl[i] = love[i][0];
        for (int j = 1; j < N; ++j) {
            ex_girl[i] = max(ex_girl[i], love[i][j]);
        }
    }

    // 尝试为每一个女生解决归宿问题
    for (int i = 0; i < N; ++i) {

        fill(slack, slack + N, INF);    // 因为要取最小值 初始化为无穷大

        while (1) {
            // 为每个女生解决归宿问题的方法是 :如果找不到就降低期望值,直到找到为止

            // 记录每轮匹配中男生女生是否被尝试匹配过
            memset(vis_girl, false, sizeof vis_girl);
            memset(vis_boy, false, sizeof vis_boy);

            if (dfs(i)) break;  // 找到归宿 退出

            // 如果不能找到 就降低期望值
            // 最小可降低的期望值
            int d = INF;
            for (int j = 0; j < N; ++j)
                if (!vis_boy[j]) d = min(d, slack[j]);//未匹配女孩与其他相关男孩的最小差值

            for (int j = 0; j < N; ++j) {
                // 所有访问过的女生降低期望值
                if (vis_girl[j]) ex_girl[j] -= d;

                // 所有访问过的男生增加期望值
                if (vis_boy[j]) ex_boy[j] += d;
                // 没有访问过的boy 因为girl们的期望值降低,距离得到女生倾心又进了一步!
                else slack[j] -= d;
            }
        }
    }

    // 匹配完成 求出所有配对的好感度的和
    int res = 0;
    for (int i = 0; i < N; ++i)
        res += love[ match[i] ][i];

    return res;
}

int main()
{
    while (~scanf("%d", &N)) {

        for (int i = 0; i < N; ++i)
            for (int j = 0; j < N; ++j)
                scanf("%d", &love[i][j]);

        printf("%d\n", KM());
    }
    return 0;
}

强连通分量,tarjan算法

#include<cstdio>
#include<algorithm>
#include<string.h>
using namespace std;
struct node {
    int v,next;
}edge[1001];
int DFN[1001],LOW[1001];
int stack[1001],heads[1001],visit[1001],cnt,tot,index;
void add(int x,int y)
{
    edge[++cnt].next=heads[x];
    edge[cnt].v = y;
    heads[x]=cnt;
    return ;
}
void tarjan(int x)//代表第几个点在处理。递归的是点。
{
    DFN[x]=LOW[x]=++tot;// 新进点的初始化。
    stack[++index]=x;//进站
    visit[x]=1;//表示在栈里
    for(int i=heads[x];i!=-1;i=edge[i].next)
    {
        if(!DFN[edge[i].v]) {//如果没访问过
            tarjan(edge[i].v);//往下进行延伸,开始递归
            LOW[x]=min(LOW[x],LOW[edge[i].v]);//递归出来,比较谁是谁的儿子/父亲,就是树的对应关系,涉及到强连通分量子树最小根的事情。
        }
        else if(visit[edge[i].v ]){  //如果访问过,并且还在栈里。
            LOW[x]=min(LOW[x],DFN[edge[i].v]);//比较谁是谁的儿子/父亲。就是链接对应关系
        }
    }
    if(LOW[x]==DFN[x]) //发现是整个强连通分量子树里的最小根。
    {
        do{
            printf("%d ",stack[index]);
            visit[stack[index]]=0;
            index--;
        }while(x!=stack[index+1]);//出栈,并且输出。
        printf("\n");
    }
    return ;
}
int main()
{
    memset(heads,-1,sizeof(heads));
    int n,m;
    scanf("%d%d",&n,&m);
    int x,y;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y);
    }
    for(int i=1;i<=n;i++)
         if(!DFN[i])  tarjan(1);//当这个点没有访问过,就从此点开始。防止图没走完
    return 0;
}

最小费用最大流

dijkstra算法

#include "stdafx.h"
#include <iostream>
#include <algorithm>
#include <queue>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <functional>

#define MAXN 5050
#define INF 0x3f3f3f3f
#define P pair<int,int>

using namespace std;

struct edge
{
    int to, cap, cost, rev;
};

int n, m, s, t;
int u, v, c, w;
int maxFlow, minCost;

vector<edge> G[MAXN];
int h[MAXN];
int dist[MAXN], prevv[MAXN], preve[MAXN];

void addedge(int from, int to, int cap, int cost)
{
    edge temp1 = { to, cap, cost, (int)G[to].size() };
    edge temp2 = { from, 0, -cost, (int)G[from].size() - 1 };
    G[from].push_back(temp1);
    G[to].push_back(temp2);
}

//Dijkstra算法实现
void MCMF(int s, int t, int f)
{
    fill(h + 1, h + 1 + n, 0);
    while (f > 0)
    {
        priority_queue<P, vector<P>, greater<P> > D;
        memset(dist, INF, sizeof dist);
        dist[s] = 0; D.push(P(0, s));
        while (!D.empty())
        {
            P now = D.top(); D.pop();
            if (dist[now.second] < now.first) continue;
            int v = now.second;
            for (int i = 0; i<(int)G[v].size(); ++i)
            {
                edge &e = G[v][i];
                if (e.cap > 0 && dist[e.to] > dist[v] + e.cost + h[v] - h[e.to])
                {
                    dist[e.to] = dist[v] + e.cost + h[v] - h[e.to];
                    prevv[e.to] = v;
                    preve[e.to] = i;
                    D.push(P(dist[e.to], e.to));
                }
            }
        }
        if (dist[t] == INF) break;
        for (int i = 1; i <= n; ++i) h[i] += dist[i];
        int d = f;
        for (int v = t; v != s; v = prevv[v])
            d = min(d, G[prevv[v]][preve[v]].cap);
        f -= d; maxFlow += d;
        minCost += d * h[t];
        for (int v = t; v != s; v = prevv[v])
        {
            edge &e = G[prevv[v]][preve[v]];
            e.cap -= d;
            G[v][e.rev].cap += d;
        }
    }
}

int _tmain(int argc, _TCHAR* argv[])
{

    cout << "节点数为:"; cin >> n;
    cout << "边数为:"; cin >> m;
    cout << "源点编号为:"; cin >> s;
    cout << "汇点编号为:"; cin >> t;

    cout << "输入 " << m << " 条边的信息:" << endl;
    while (m--)
    {
        cout << "起点:"; cin >> u;
        cout << "终点:"; cin >> v;
        cout << "容量:"; cin >> c;
        cout << "费用:"; cin >> w;
        cout << "-----------------" << endl;
        addedge(u, v, c, w);
    }

    MCMF(s, t, INF);

    cout << "最大流为:" << maxFlow << endl;
    cout << "最小费用为" << minCost << endl;
    cout << endl;

    system("pause");
    return 0;
}
————————————————
版权声明:本文为CSDN博主「WhiteJunior」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lym940928/java/article/details/90209172

哈密顿回路

/*
Icosian Game A century after Euler’s discovery (see Problem 4), another
famous puzzle—this one invented by the renowned Irish mathematician Sir
William Hamilton (1805–1865)—was presented to the world under the name
of the Icosian Game.
Find a Hamiltonian circuit—a path that visits all the graph’s vertices exactly
once before returning to the starting vertex
*/

#include <iostream>
#include <vector>

using namespace std;

bool hamiltonian(vector<vector<bool>>& graph, vector<bool>& visit, int vertex, vector<int>& path) {
    path.push_back(vertex);
    if (path.size() == graph.size() + 1 && vertex == path[0]) {
        cout << "-----begin solution-----" << endl;
        for (size_t i = 0; i < path.size(); ++i) {
            cout << path[i];
            if (i != path.size() - 1)
                cout << "-->";
        }
        cout << endl << "-----end solution-----" << endl;
        return true;
    }
    if (vertex == path[0] && path.size() != 1) {
        path.pop_back();
        return false;
    }
    for (size_t i = 0; i < graph.size(); ++i) {
        if (graph[vertex][i] && (!visit[i] || i == path[0])) {
            visit[vertex] = true;
            if (hamiltonian(graph, visit, i, path))
                return true;
            visit[vertex] = false;
        }
    }
    path.pop_back();
    return false;
}

int main() {
    /*
    (0)--(1)--(2)
    |   / \   |
    |  /   \  | 
    | /     \ |
    (3)-------(4)
    */
    vector<vector<bool>> graph = {
        {0, 1, 0, 1, 0},
        {1, 0, 1, 1, 1},
        {0, 1, 0, 0, 1},
        {1, 1, 0, 0, 1},
        {0, 1, 1, 1, 0}
    };
    for (auto& g : graph) {
        for (const auto& e : g) {
            cout << e;
        }
        cout << endl;
    }
    vector<int> path;
    vector<bool> visit(graph.size(), false);
    hamiltonian(graph, visit, 0, path);
    /* result:
    -----begin solution-----
    0-->1-->2-->4-->3-->0
    -----end solution-----
    */
    return 0;
}

字符串

Boyer-Moore-Horsepool

class Solution {
public:
    int strStr(string haystack, string needle) {
        int m = haystack.size(), n = needle.size();
        
        if (n == 0) {
            return 0;
        }
        
        if (m < n) {
            return -1;
        }
        
        vector<int> badCharShift(256, n);
        
        int last = n - 1;
        for (int i = 0; i < last; ++i) {
            badCharShift[needle[i]] = last - i;
        }
        
        int p = 0;
        
        while (m - p >= n) {
            for (int i = last; haystack[p + i] == needle[i]; --i) {
                if (i == 0) {
                    return p;
                }
            }
            
            // cout << p << ' ' << haystack.substr(p, n) << endl;
            
            p += badCharShift[haystack[p + last]];
        }
        
        return -1;
    }
};

排序

排序链表

Qsort

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */

using namespace std;

class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if (head == NULL) {
            return NULL;
        }
        
        return get<0>(qsort(head));
    }
private:
    tuple<ListNode*, ListNode*> qsort(ListNode* head) {
        if (head -> next == NULL) {
            return make_tuple(head, head);
        }
        
        ListNode* left = NULL, *left_end = NULL, *right = NULL, *right_end = NULL;
        
        ListNode* p = head -> next;
        int k = head->val;
        head -> next = NULL;
        
        while (p != NULL) {
            ListNode* next = p -> next;
            p -> next = NULL;
            
            if (p -> val < k) {
                if (left == NULL) {
                    left = left_end = p;
                }
                else {
                    left_end -> next = p;
                    left_end = p;
                }
            }
            else {
                if (right == NULL) {
                    right = right_end = p;
                }
                else {
                    right_end -> next = p;
                    right_end = p;
                }
            }
            
            p = next;
        }
        
        if (left != NULL) {
            tie(left, left_end) = qsort(left);
        }
        
        if (right != NULL) {
            tie(right, right_end) = qsort(right);
        }
        
        if (left == NULL) {
            left = head;
        }
        else {
            left_end -> next = head;
        }
        
        if (right == NULL) {
            head -> next = NULL;
            right_end = head;
        }
        else {
            head -> next = right;
        }
        
        return make_tuple(left, right_end);
    }
};

归并

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */

using namespace std;

class Solution {
public:
    ListNode* sortList(ListNode* head) {
        int length = 0;
        
        ListNode* p = head;
        
        while (p != NULL) {
            ++length;
            p = p -> next;
        }
        
        if (length == 0) {
            return NULL;
        }
        
        auto dummpy = ListNode();
        auto rst = &dummpy;
        rst -> next = head;
        auto rst_end = rst;
        
        for (int step = 1; step < length; step *= 2) {
            auto current = rst -> next;
            auto rst_end = rst;
            
            ListNode* left, *right;
            
            while (current) {
                left = current;
            
                right = cut(current, step);

                current = cut(right, step);

                ListNode* new_end = NULL;
                tie(rst_end -> next, new_end) = merge(left, right);
                
                rst_end = new_end;
            }
        }
        
        return rst -> next;
    }

private:
    ListNode* cut(ListNode* head, int n) {
        auto p = head;
        while (--n && p) {
            p = p -> next;
        }
        
        ListNode* next = NULL;
        if (p) {
            next = p -> next;
            p -> next = NULL;
        }
        
        return next;
    }
    
    tuple<ListNode*, ListNode*> merge(ListNode* left, ListNode* right) {
        auto dummpy = ListNode();
        auto ret = &dummpy;
        ret -> next = NULL;
        auto ret_end = ret;
        
        auto p = left;
        auto q = right;
        
        while (p && q) {
            if (p -> val < q -> val) {
                ret_end -> next = p;
                ret_end = p;
                p = p -> next;
            }
            else {
                ret_end -> next = q;
                ret_end = q;
                q = q -> next;
            }
        }
        
        while (p) {
            ret_end -> next = p;
            ret_end = p;
            p = p -> next;
        }
        
        while (q) {
            ret_end -> next = q;
            ret_end = q;
            q = q -> next;
        }
        
        ret_end -> next = NULL;
        
        return make_tuple(ret -> next, ret_end);
    }
};

二分搜索

// 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int n = nums.size();

        int p = 0, q = n;

        while (p < q) {
            int r = (p + q) >> 1;

            if (nums[r] == target) {
                return r;
            }
            else if (nums[r] < target) {
                p = r + 1;
            }
            else {
                q = r;
            }
        }

        return p;
    }
};

选择

快速选择

class Solution {
public:
    int quickSelect(vector<int>& a, int l, int r, int index) {
        int q = randomPartition(a, l, r);
        if (q == index) {
            return a[q];
        } else {
            return q < index ? quickSelect(a, q + 1, r, index) : quickSelect(a, l, q - 1, index);
        }
    }

    inline int randomPartition(vector<int>& a, int l, int r) {
        int i = rand() % (r - l + 1) + l;
        swap(a[i], a[r]);
        return partition(a, l, r);
    }

    inline int partition(vector<int>& a, int l, int r) {
        int x = a[r], i = l - 1;
        for (int j = l; j < r; ++j) {
            if (a[j] <= x) {
                swap(a[++i], a[j]);
            }
        }
        swap(a[i + 1], a[r]);
        return i + 1;
    }

    int findKthLargest(vector<int>& nums, int k) {
        srand(time(0));
        return quickSelect(nums, 0, nums.size() - 1, nums.size() - k);
    }
};

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/kth-largest-element-in-an-array/solution/shu-zu-zhong-de-di-kge-zui-da-yuan-su-by-leetcode-/

相关文章

  • 常用算法模板

    动态规划(记忆化搜索) 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数...

  • C++ 学习之(一):面试中的算法和准备过程

    面试中的算法和准备过程 从一道入门题说起 为什么要学习算法 如何准备面试算法 代码风格 了解算法面试的模板 常用工...

  • Java算法竞赛常用模板

    Java算法竞赛常用模板 一、输入输出 简单输入 测试: abcsc1:7968695900abcabcsc2:1...

  • 第二章 C++ STL 泛型编程 1

    一、STL 概述 STL——C++标准模板库,定义了常用的数据结构和算法。提供三种类型的组件:容器、迭代器和算法。...

  • 计算机视觉 OpenCV Android | 基本特征检测 之

    模板匹配的 概述 以及 使用简介 模板匹配是最简单的模式识别算法之一,其在图像处理中经常用于从一副未知图像中,根据...

  • 模板模式

    概述 模板模式是在框架和实际编程当中常用到的编程方法。在书中看到模板模式的定义如下:定义一个操作中算法的骨架,而将...

  • 【算法常用模板】总结(更新中)

    搜索类 图类 排序类 并查集 数学类 位运算 Part1 搜索类 bfs 求迷宫问题最短路径(未验证) dfs 求...

  • OpenCV使用(二):模板匹配实现人脸识别

    目录 效果展示 什么是模板匹配 模板匹配是最简单的模式识别算法之一,其在图像处理中经常用于从一副未知图像中根据预先...

  • opencv目标跟踪算法 - 草稿

    * kcf算法 * orb算法 * meanshift算法 * camshift * klt * tld * 模板匹配

  • 算法与数据结构

    五大常用算法之一:分治算法 五大常用算法之二:动态规划算法 五大常用算法之三:贪心算法 五大常用算法之四:回溯法 ...

网友评论

      本文标题:常用算法模板

      本文链接:https://www.haomeiwen.com/subject/fticlktx.html