├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── 01-algo-website-bug.md │ ├── 02-algo-visualize-bug.md │ ├── 03-chrome-extension-bug.md │ ├── 04-vscode-extension-bug.md │ ├── 05-jetbrain-plugin-bug.md │ └── 06-suggestion.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── README.md ├── contributor.jpg ├── pictures ├── 4keyboard │ ├── 1.jpg │ └── title.png ├── BST │ ├── BST_example.png │ ├── bst_deletion_case_1.png │ ├── bst_deletion_case_2.png │ ├── bst_deletion_case_3.png │ └── 假BST.png ├── Chrome插件 │ ├── baidumonkey.png │ ├── baidu广告.png │ ├── csdnBlock.png │ ├── githubzip.png │ ├── listen1.png │ ├── monkey.png │ ├── oneTab.png │ ├── pin.png │ ├── tree.png │ └── youhou优化.png ├── LCS │ ├── 1.png │ ├── 2.png │ ├── 3.png │ ├── dp.png │ └── lcs.png ├── LRU算法 │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ └── put.jpg ├── algo4 │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ └── title.png ├── backtrack │ ├── ink-image (1).png │ ├── ink-image (2).png │ ├── ink-image (3).png │ ├── ink-image (4).png │ ├── ink-image (5).png │ ├── ink-image (6).png │ ├── ink-image.png │ ├── nqueens.png │ ├── permutation.png │ ├── 代码.png │ ├── 代码1.png │ ├── 代码2.png │ ├── 代码3.png │ └── 全排列.png ├── backtracking │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ ├── 6.jpg │ └── 7.jpg ├── calculator │ ├── 1.1.jpg │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ └── 6.jpg ├── cover.jpg ├── dupmissing │ ├── 1.gif │ ├── 2.jpg │ └── 3.jpg ├── editDistance │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ ├── 6.jpg │ ├── delete.gif │ ├── dp.jpg │ ├── edit.gif │ ├── insert.gif │ ├── replace.gif │ └── title.png ├── floodfill │ ├── floodfill.gif │ ├── floodfill.png │ ├── leetcode.png │ ├── ppt1.PNG │ ├── ppt2.PNG │ ├── ppt3.PNG │ ├── ppt4.PNG │ ├── ppt5.PNG │ ├── xiaoxiaole.jpg │ ├── 扫雷.png │ ├── 抠图.jpeg │ └── 抠图.jpg ├── group.jpg ├── header.jpg ├── heap │ ├── 1.png │ ├── delete.gif │ ├── insert.gif │ ├── sink.gif │ └── swim.gif ├── intersection │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.gif │ └── title.png ├── interval │ ├── 1.gif │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── title1.png │ └── title2.png ├── kgroup │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ ├── 6.jpg │ ├── 7.jpg │ ├── 8.gif │ └── title.png ├── kmp │ ├── 1.gif │ ├── 2.gif │ ├── 3.gif │ ├── A.gif │ ├── allstate.jpg │ ├── back.jpg │ ├── dfa.gif │ ├── exp1.jpg │ ├── exp2.jpg │ ├── exp3.jpg │ ├── exp4.jpg │ ├── exp5.jpg │ ├── exp6.jpg │ ├── exp7.jpg │ ├── forward.jpg │ ├── kmp.gif │ ├── shadow.jpg │ ├── shadow1.jpg │ ├── shadow2.jpg │ ├── state.jpg │ ├── state2.jpg │ ├── state4.jpg │ ├── txt1.jpg │ ├── txt2.jpg │ ├── txt3.jpg │ ├── txt4.jpg │ └── z.jpg ├── labuladong.png ├── linux-fs │ ├── application.png │ ├── apt.png │ ├── bin.png │ ├── boot.png │ ├── cpu.png │ ├── desktop.png │ ├── dev.png │ ├── etc.png │ ├── home.png │ ├── linux-filesystem.png │ ├── log.png │ ├── opt.png │ ├── proc.png │ ├── root.png │ ├── sbin.png │ ├── tmp.png │ ├── usr.png │ └── usrbin.png ├── linuxProcess │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ ├── 6.jpg │ ├── 7.jpg │ └── 8.jpg ├── linuxshell │ └── 1.png ├── mergeInterval │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.gif │ └── title.png ├── online │ ├── 1.png │ ├── 10.png │ ├── 11.png │ ├── 2.png │ ├── 3.png │ ├── 4.png │ ├── 5.png │ ├── 6.png │ ├── 7.png │ ├── 8.png │ └── 9.png ├── others │ └── leetcode.jpeg ├── pancakeSort │ ├── 1.jpg │ ├── 2.png │ ├── 3.jpg │ ├── 4.jpg │ └── title.png ├── pay.jpg ├── plugin │ ├── chrome.gif │ ├── chrome.jpg │ ├── jetbrain.gif │ ├── jetbrain.jpg │ ├── vscode.gif │ ├── vscode.jpg │ └── 全家桶.jpg ├── prime │ └── 1.gif ├── qrcode.jpg ├── redis入侵 │ ├── 1.png │ ├── 2.png │ ├── 3.png │ ├── 4.png │ ├── 5.png │ └── 6.png ├── robber │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── title.png │ └── title1.png ├── session │ ├── 1.png │ ├── 2.png │ ├── 3.png │ └── 4.jpg ├── souyisou.png ├── souyisou2.png ├── unionfind │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ ├── 6.jpg │ ├── 7.jpg │ ├── 8.jpg │ └── 9.gif ├── unionfind应用 │ ├── 1.jpg │ ├── 2.jpg │ └── 3.jpg ├── youtube │ ├── 1.png │ ├── 1573133096614.jpeg │ ├── 1573133131308.jpeg │ ├── 2.jpg │ ├── 3.jpg │ └── 4.jpg ├── 二分应用 │ ├── title1.png │ └── title2.png ├── 二分查找 │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── binarySearch1.png │ ├── binarySearch2.png │ └── poem.png ├── 位操作 │ ├── 1.png │ └── title.png ├── 信封嵌套 │ ├── 0.jpg │ ├── 1.jpg │ ├── 2.jpg │ └── title.png ├── 全家桶.jpg ├── 前缀和 │ ├── 1.jpg │ ├── 2.jpg │ └── title.png ├── 动态规划详解 │ ├── coindp.png │ ├── coinfunc.png │ ├── cointree.png │ ├── fibdp.png │ ├── fibfunc.png │ ├── fibmemo.png │ ├── fibtree.png │ ├── img_20190514_013033.441.png │ ├── img_20190514_013830.397.png │ ├── ink-image (1).png │ ├── ink-image (2).png │ ├── ink-image (3).png │ ├── ink-image (4).png │ └── ink-image.png ├── 动态规划详解进阶 │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ ├── 6.jpg │ ├── coin.png │ └── fib.png ├── 单调栈 │ ├── 1.png │ ├── 2.png │ └── 3.png ├── 单调队列 │ ├── 1.png │ ├── 2.png │ ├── 3.png │ └── title.png ├── 博弈问题 │ ├── 1.png │ ├── 2.png │ ├── 3.png │ └── 4.png ├── 双指针 │ ├── 1.png │ ├── 2.png │ ├── 3.png │ ├── center.png │ └── title.png ├── 反转链表 │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ ├── 6.jpg │ ├── 7.jpg │ └── title.png ├── 回文 │ └── title.png ├── 回文链表 │ ├── 1.gif │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ └── 4.jpg ├── 子序列 │ ├── 1.gif │ ├── 1.jpg │ ├── 2.gif │ ├── 2.jpg │ └── 3.jpg ├── 子集 │ ├── 1.jpg │ ├── 2.jpg │ └── 3.jpg ├── 字符串乘法 │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.gif │ ├── 6.jpg │ └── title.png ├── 密码技术 │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ ├── 6.jpg │ └── 7.jpg ├── 座位调度 │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ ├── 6.jpg │ └── 7.jpg ├── 扔鸡蛋 │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ └── dp.png ├── 接雨水 │ ├── 0.jpg │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ └── title.png ├── 数组交换 │ ├── ink-image (1).png │ ├── ink-image (2).png │ ├── ink-image (3).png │ └── ink-image.png ├── 最优子结构 │ └── 1.jpg ├── 最长回文子序列 │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ └── 5.jpg ├── 最长递增子序列 │ ├── 1.jpeg │ ├── 2.jpeg │ ├── 3.jpeg │ ├── gif1.gif │ ├── gif2.gif │ ├── poker1.jpeg │ ├── poker2.jpeg │ ├── poker3.jpeg │ ├── poker4.jpeg │ └── title.png ├── 有序数组去重 │ ├── 1.gif │ ├── 2.gif │ └── title.png ├── 栈队列 │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ └── 6.jpg ├── 概率问题 │ ├── p.png │ ├── p.svg │ ├── sanmen.png │ ├── sanmen.svg │ └── tree.png ├── 正则 │ ├── 1.jpeg │ ├── 2.jpeg │ ├── 3.jpeg │ ├── 4.jpeg │ ├── example.png │ └── title.png ├── 洗牌算法 │ ├── 1.png │ ├── 2.png │ ├── 3.png │ ├── 4.png │ ├── 5.jpg │ └── 6.png ├── 滑动窗口 │ ├── 0.png │ ├── 1.png │ ├── 2.png │ ├── 3.png │ ├── title1.png │ ├── title2.png │ └── title3.png ├── 缺失元素 │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── title.png │ └── xor.png ├── 股票问题 │ ├── 1.png │ └── title.png └── 设计Twitter │ ├── design.png │ ├── merge.gif │ ├── tweet.jpg │ └── user.jpg ├── starHistory.jpg ├── starHistory.png ├── 动态规划系列 ├── LCS.md ├── README.md ├── 动态规划之KMP字符匹配算法.md ├── 动态规划之博弈问题.md ├── 动态规划之四键键盘.md ├── 动态规划之正则表达.md ├── 动态规划设计:最长递增子序列.md ├── 动态规划详解进阶.md ├── 单词拼接.md ├── 团灭股票问题.md ├── 子序列问题模板.md ├── 抢房子.md ├── 最优子结构.md ├── 状态压缩技巧.md ├── 编辑距离.md ├── 背包问题.md ├── 贪心算法之区间调度问题.md ├── 高楼扔鸡蛋问题.md └── 魔塔.md ├── 多语言解法代码 ├── contribution-guide.md └── solution_code.md ├── 技术 ├── linuxshell.md ├── linux进程.md ├── redis入侵.md ├── session和cookie.md ├── 刷题技巧.md ├── 在线练习平台.md └── 密码技术.md ├── 数据结构系列 ├── BST1.md ├── BST2.md ├── README.md ├── dijkstra算法.md ├── 二叉堆详解实现优先级队列.md ├── 二叉树总结.md ├── 二叉树系列1.md ├── 二叉树系列2.md ├── 单调栈.md ├── 单调队列.md ├── 图.md ├── 实现计算器.md ├── 拓扑排序.md ├── 设计Twitter.md ├── 递归反转链表的一部分.md └── 队列实现栈栈实现队列.md ├── 算法思维系列 ├── BFS框架.md ├── BFS解决滑动拼图.md ├── README.md ├── UnionFind算法详解.md ├── 二分查找详解.md ├── 几个反直觉的概率问题.md ├── 前缀和技巧.md ├── 双指针技巧.md ├── 回溯算法详解修订版.md ├── 字符串乘法.md ├── 学习数据结构和算法的高效方法.md ├── 差分技巧.md ├── 常用的位操作.md ├── 洗牌算法.md ├── 滑动窗口技巧进阶.md ├── 烧饼排序.md ├── 花式遍历.md └── 集合划分.md └── 高频面试系列 ├── LRU算法.md ├── README.md ├── k个一组反转链表.md ├── 一行代码解决的智力题.md ├── 二分查找判定子序列.md ├── 二分运用.md ├── 判断回文链表.md ├── 名人问题.md ├── 子集排列组合.md ├── 安排会议室.md ├── 岛屿题目.md ├── 座位调度.md ├── 打印素数.md ├── 接雨水.md ├── 缺失和重复的元素.md └── 随机权重.md /.gitattributes: -------------------------------------------------------------------------------- 1 | *.md linguist-detectable=true 2 | *.md linguist-documentation=false -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/01-algo-website-bug.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Website bug 3 | about: Report bug on website `labuladong.online` 4 | title: '' 5 | labels: algo-websie-bug 6 | assignees: labuladong 7 | 8 | --- 9 | 10 | **Network condition:** 11 | China network or Global network? 12 | 13 | **Describe the bug** 14 | A clear and concise description of what the bug is. 15 | 16 | **Screenshots** 17 | If applicable, add screenshots to help explain your problem. 18 | 19 | **Platform** 20 | Mobile phone or PC? 21 | What kind of web browser? (chrome/edge/...) 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/02-algo-visualize-bug.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Algo-visualize bug 3 | about: Report bug for algo-visualize tool in website/plugins 4 | title: '' 5 | labels: algo-visualize-bug 6 | assignees: labuladong 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/03-chrome-extension-bug.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Chrome extension bug 3 | about: Report bug on Chrome extension 4 | title: '' 5 | labels: algo-website, chrome-extension-bug 6 | assignees: labuladong 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **Screenshots** 14 | If applicable, add screenshots to help explain your problem. 15 | 16 | **Platform** 17 | What kind of web browser are you using? (chrome/edge/...) 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/04-vscode-extension-bug.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: VSCode extension bug 3 | about: Report bug on vscode extension 4 | title: '' 5 | labels: vscode-extension-bug 6 | assignees: labuladong 7 | 8 | --- 9 | 10 | **Version:** 11 | What's the extension version are you using? 12 | 13 | **Describe the bug** 14 | A clear and concise description of what the bug is. 15 | 16 | **Screenshots** 17 | If applicable, add screenshots to help explain your problem. 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/05-jetbrain-plugin-bug.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: JetBrain plugin bug 3 | about: Report bug on JetBrain plugin 4 | title: '' 5 | labels: jb-plugin-bug 6 | assignees: labuladong 7 | 8 | --- 9 | 10 | **Version:** 11 | What's the plugin version are you using? 12 | 13 | **Describe the bug** 14 | A clear and concise description of what the bug is. 15 | 16 | **Screenshots** 17 | If applicable, add screenshots to help explain your problem. 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/06-suggestion.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Suggestion 3 | about: Suggest an idea/improvement for this project 4 | title: '' 5 | labels: feature-request 6 | assignees: labuladong 7 | 8 | --- 9 | 10 | Do you have any suggestions? 11 | 12 | Is there anything that you feel inconvenient to use? 13 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/.github/PULL_REQUEST_TEMPLATE.md -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_store 2 | -------------------------------------------------------------------------------- /contributor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/contributor.jpg -------------------------------------------------------------------------------- /pictures/4keyboard/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/4keyboard/1.jpg -------------------------------------------------------------------------------- /pictures/4keyboard/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/4keyboard/title.png -------------------------------------------------------------------------------- /pictures/BST/BST_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/BST/BST_example.png -------------------------------------------------------------------------------- /pictures/BST/bst_deletion_case_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/BST/bst_deletion_case_1.png -------------------------------------------------------------------------------- /pictures/BST/bst_deletion_case_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/BST/bst_deletion_case_2.png -------------------------------------------------------------------------------- /pictures/BST/bst_deletion_case_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/BST/bst_deletion_case_3.png -------------------------------------------------------------------------------- /pictures/BST/假BST.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/BST/假BST.png -------------------------------------------------------------------------------- /pictures/Chrome插件/baidumonkey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/Chrome插件/baidumonkey.png -------------------------------------------------------------------------------- /pictures/Chrome插件/baidu广告.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/Chrome插件/baidu广告.png -------------------------------------------------------------------------------- /pictures/Chrome插件/csdnBlock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/Chrome插件/csdnBlock.png -------------------------------------------------------------------------------- /pictures/Chrome插件/githubzip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/Chrome插件/githubzip.png -------------------------------------------------------------------------------- /pictures/Chrome插件/listen1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/Chrome插件/listen1.png -------------------------------------------------------------------------------- /pictures/Chrome插件/monkey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/Chrome插件/monkey.png -------------------------------------------------------------------------------- /pictures/Chrome插件/oneTab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/Chrome插件/oneTab.png -------------------------------------------------------------------------------- /pictures/Chrome插件/pin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/Chrome插件/pin.png -------------------------------------------------------------------------------- /pictures/Chrome插件/tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/Chrome插件/tree.png -------------------------------------------------------------------------------- /pictures/Chrome插件/youhou优化.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/Chrome插件/youhou优化.png -------------------------------------------------------------------------------- /pictures/LCS/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/LCS/1.png -------------------------------------------------------------------------------- /pictures/LCS/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/LCS/2.png -------------------------------------------------------------------------------- /pictures/LCS/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/LCS/3.png -------------------------------------------------------------------------------- /pictures/LCS/dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/LCS/dp.png -------------------------------------------------------------------------------- /pictures/LCS/lcs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/LCS/lcs.png -------------------------------------------------------------------------------- /pictures/LRU算法/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/LRU算法/1.jpg -------------------------------------------------------------------------------- /pictures/LRU算法/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/LRU算法/2.jpg -------------------------------------------------------------------------------- /pictures/LRU算法/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/LRU算法/3.jpg -------------------------------------------------------------------------------- /pictures/LRU算法/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/LRU算法/4.jpg -------------------------------------------------------------------------------- /pictures/LRU算法/put.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/LRU算法/put.jpg -------------------------------------------------------------------------------- /pictures/algo4/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/algo4/1.jpg -------------------------------------------------------------------------------- /pictures/algo4/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/algo4/2.jpg -------------------------------------------------------------------------------- /pictures/algo4/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/algo4/3.jpg -------------------------------------------------------------------------------- /pictures/algo4/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/algo4/title.png -------------------------------------------------------------------------------- /pictures/backtrack/ink-image (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/backtrack/ink-image (1).png -------------------------------------------------------------------------------- /pictures/backtrack/ink-image (2).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/backtrack/ink-image (2).png -------------------------------------------------------------------------------- /pictures/backtrack/ink-image (3).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/backtrack/ink-image (3).png -------------------------------------------------------------------------------- /pictures/backtrack/ink-image (4).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/backtrack/ink-image (4).png -------------------------------------------------------------------------------- /pictures/backtrack/ink-image (5).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/backtrack/ink-image (5).png -------------------------------------------------------------------------------- /pictures/backtrack/ink-image (6).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/backtrack/ink-image (6).png -------------------------------------------------------------------------------- /pictures/backtrack/ink-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/backtrack/ink-image.png -------------------------------------------------------------------------------- /pictures/backtrack/nqueens.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/backtrack/nqueens.png -------------------------------------------------------------------------------- /pictures/backtrack/permutation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/backtrack/permutation.png -------------------------------------------------------------------------------- /pictures/backtrack/代码.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/backtrack/代码.png -------------------------------------------------------------------------------- /pictures/backtrack/代码1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/backtrack/代码1.png -------------------------------------------------------------------------------- /pictures/backtrack/代码2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/backtrack/代码2.png -------------------------------------------------------------------------------- /pictures/backtrack/代码3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/backtrack/代码3.png -------------------------------------------------------------------------------- /pictures/backtrack/全排列.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/backtrack/全排列.png -------------------------------------------------------------------------------- /pictures/backtracking/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/backtracking/1.jpg -------------------------------------------------------------------------------- /pictures/backtracking/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/backtracking/2.jpg -------------------------------------------------------------------------------- /pictures/backtracking/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/backtracking/3.jpg -------------------------------------------------------------------------------- /pictures/backtracking/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/backtracking/4.jpg -------------------------------------------------------------------------------- /pictures/backtracking/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/backtracking/5.jpg -------------------------------------------------------------------------------- /pictures/backtracking/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/backtracking/6.jpg -------------------------------------------------------------------------------- /pictures/backtracking/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/backtracking/7.jpg -------------------------------------------------------------------------------- /pictures/calculator/1.1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/calculator/1.1.jpg -------------------------------------------------------------------------------- /pictures/calculator/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/calculator/1.jpg -------------------------------------------------------------------------------- /pictures/calculator/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/calculator/2.jpg -------------------------------------------------------------------------------- /pictures/calculator/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/calculator/3.jpg -------------------------------------------------------------------------------- /pictures/calculator/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/calculator/4.jpg -------------------------------------------------------------------------------- /pictures/calculator/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/calculator/5.jpg -------------------------------------------------------------------------------- /pictures/calculator/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/calculator/6.jpg -------------------------------------------------------------------------------- /pictures/cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/cover.jpg -------------------------------------------------------------------------------- /pictures/dupmissing/1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/dupmissing/1.gif -------------------------------------------------------------------------------- /pictures/dupmissing/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/dupmissing/2.jpg -------------------------------------------------------------------------------- /pictures/dupmissing/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/dupmissing/3.jpg -------------------------------------------------------------------------------- /pictures/editDistance/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/editDistance/1.jpg -------------------------------------------------------------------------------- /pictures/editDistance/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/editDistance/2.jpg -------------------------------------------------------------------------------- /pictures/editDistance/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/editDistance/3.jpg -------------------------------------------------------------------------------- /pictures/editDistance/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/editDistance/4.jpg -------------------------------------------------------------------------------- /pictures/editDistance/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/editDistance/5.jpg -------------------------------------------------------------------------------- /pictures/editDistance/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/editDistance/6.jpg -------------------------------------------------------------------------------- /pictures/editDistance/delete.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/editDistance/delete.gif -------------------------------------------------------------------------------- /pictures/editDistance/dp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/editDistance/dp.jpg -------------------------------------------------------------------------------- /pictures/editDistance/edit.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/editDistance/edit.gif -------------------------------------------------------------------------------- /pictures/editDistance/insert.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/editDistance/insert.gif -------------------------------------------------------------------------------- /pictures/editDistance/replace.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/editDistance/replace.gif -------------------------------------------------------------------------------- /pictures/editDistance/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/editDistance/title.png -------------------------------------------------------------------------------- /pictures/floodfill/floodfill.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/floodfill/floodfill.gif -------------------------------------------------------------------------------- /pictures/floodfill/floodfill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/floodfill/floodfill.png -------------------------------------------------------------------------------- /pictures/floodfill/leetcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/floodfill/leetcode.png -------------------------------------------------------------------------------- /pictures/floodfill/ppt1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/floodfill/ppt1.PNG -------------------------------------------------------------------------------- /pictures/floodfill/ppt2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/floodfill/ppt2.PNG -------------------------------------------------------------------------------- /pictures/floodfill/ppt3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/floodfill/ppt3.PNG -------------------------------------------------------------------------------- /pictures/floodfill/ppt4.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/floodfill/ppt4.PNG -------------------------------------------------------------------------------- /pictures/floodfill/ppt5.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/floodfill/ppt5.PNG -------------------------------------------------------------------------------- /pictures/floodfill/xiaoxiaole.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/floodfill/xiaoxiaole.jpg -------------------------------------------------------------------------------- /pictures/floodfill/扫雷.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/floodfill/扫雷.png -------------------------------------------------------------------------------- /pictures/floodfill/抠图.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/floodfill/抠图.jpeg -------------------------------------------------------------------------------- /pictures/floodfill/抠图.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/floodfill/抠图.jpg -------------------------------------------------------------------------------- /pictures/group.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/group.jpg -------------------------------------------------------------------------------- /pictures/header.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/header.jpg -------------------------------------------------------------------------------- /pictures/heap/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/heap/1.png -------------------------------------------------------------------------------- /pictures/heap/delete.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/heap/delete.gif -------------------------------------------------------------------------------- /pictures/heap/insert.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/heap/insert.gif -------------------------------------------------------------------------------- /pictures/heap/sink.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/heap/sink.gif -------------------------------------------------------------------------------- /pictures/heap/swim.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/heap/swim.gif -------------------------------------------------------------------------------- /pictures/intersection/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/intersection/1.jpg -------------------------------------------------------------------------------- /pictures/intersection/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/intersection/2.jpg -------------------------------------------------------------------------------- /pictures/intersection/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/intersection/3.jpg -------------------------------------------------------------------------------- /pictures/intersection/4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/intersection/4.gif -------------------------------------------------------------------------------- /pictures/intersection/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/intersection/title.png -------------------------------------------------------------------------------- /pictures/interval/1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/interval/1.gif -------------------------------------------------------------------------------- /pictures/interval/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/interval/2.jpg -------------------------------------------------------------------------------- /pictures/interval/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/interval/3.jpg -------------------------------------------------------------------------------- /pictures/interval/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/interval/4.jpg -------------------------------------------------------------------------------- /pictures/interval/title1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/interval/title1.png -------------------------------------------------------------------------------- /pictures/interval/title2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/interval/title2.png -------------------------------------------------------------------------------- /pictures/kgroup/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kgroup/1.jpg -------------------------------------------------------------------------------- /pictures/kgroup/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kgroup/2.jpg -------------------------------------------------------------------------------- /pictures/kgroup/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kgroup/3.jpg -------------------------------------------------------------------------------- /pictures/kgroup/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kgroup/4.jpg -------------------------------------------------------------------------------- /pictures/kgroup/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kgroup/5.jpg -------------------------------------------------------------------------------- /pictures/kgroup/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kgroup/6.jpg -------------------------------------------------------------------------------- /pictures/kgroup/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kgroup/7.jpg -------------------------------------------------------------------------------- /pictures/kgroup/8.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kgroup/8.gif -------------------------------------------------------------------------------- /pictures/kgroup/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kgroup/title.png -------------------------------------------------------------------------------- /pictures/kmp/1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kmp/1.gif -------------------------------------------------------------------------------- /pictures/kmp/2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kmp/2.gif -------------------------------------------------------------------------------- /pictures/kmp/3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kmp/3.gif -------------------------------------------------------------------------------- /pictures/kmp/A.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kmp/A.gif -------------------------------------------------------------------------------- /pictures/kmp/allstate.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kmp/allstate.jpg -------------------------------------------------------------------------------- /pictures/kmp/back.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kmp/back.jpg -------------------------------------------------------------------------------- /pictures/kmp/dfa.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kmp/dfa.gif -------------------------------------------------------------------------------- /pictures/kmp/exp1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kmp/exp1.jpg -------------------------------------------------------------------------------- /pictures/kmp/exp2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kmp/exp2.jpg -------------------------------------------------------------------------------- /pictures/kmp/exp3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kmp/exp3.jpg -------------------------------------------------------------------------------- /pictures/kmp/exp4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kmp/exp4.jpg -------------------------------------------------------------------------------- /pictures/kmp/exp5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kmp/exp5.jpg -------------------------------------------------------------------------------- /pictures/kmp/exp6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kmp/exp6.jpg -------------------------------------------------------------------------------- /pictures/kmp/exp7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kmp/exp7.jpg -------------------------------------------------------------------------------- /pictures/kmp/forward.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kmp/forward.jpg -------------------------------------------------------------------------------- /pictures/kmp/kmp.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kmp/kmp.gif -------------------------------------------------------------------------------- /pictures/kmp/shadow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kmp/shadow.jpg -------------------------------------------------------------------------------- /pictures/kmp/shadow1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kmp/shadow1.jpg -------------------------------------------------------------------------------- /pictures/kmp/shadow2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kmp/shadow2.jpg -------------------------------------------------------------------------------- /pictures/kmp/state.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kmp/state.jpg -------------------------------------------------------------------------------- /pictures/kmp/state2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kmp/state2.jpg -------------------------------------------------------------------------------- /pictures/kmp/state4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kmp/state4.jpg -------------------------------------------------------------------------------- /pictures/kmp/txt1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kmp/txt1.jpg -------------------------------------------------------------------------------- /pictures/kmp/txt2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kmp/txt2.jpg -------------------------------------------------------------------------------- /pictures/kmp/txt3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kmp/txt3.jpg -------------------------------------------------------------------------------- /pictures/kmp/txt4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kmp/txt4.jpg -------------------------------------------------------------------------------- /pictures/kmp/z.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/kmp/z.jpg -------------------------------------------------------------------------------- /pictures/labuladong.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/labuladong.png -------------------------------------------------------------------------------- /pictures/linux-fs/application.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/linux-fs/application.png -------------------------------------------------------------------------------- /pictures/linux-fs/apt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/linux-fs/apt.png -------------------------------------------------------------------------------- /pictures/linux-fs/bin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/linux-fs/bin.png -------------------------------------------------------------------------------- /pictures/linux-fs/boot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/linux-fs/boot.png -------------------------------------------------------------------------------- /pictures/linux-fs/cpu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/linux-fs/cpu.png -------------------------------------------------------------------------------- /pictures/linux-fs/desktop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/linux-fs/desktop.png -------------------------------------------------------------------------------- /pictures/linux-fs/dev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/linux-fs/dev.png -------------------------------------------------------------------------------- /pictures/linux-fs/etc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/linux-fs/etc.png -------------------------------------------------------------------------------- /pictures/linux-fs/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/linux-fs/home.png -------------------------------------------------------------------------------- /pictures/linux-fs/linux-filesystem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/linux-fs/linux-filesystem.png -------------------------------------------------------------------------------- /pictures/linux-fs/log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/linux-fs/log.png -------------------------------------------------------------------------------- /pictures/linux-fs/opt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/linux-fs/opt.png -------------------------------------------------------------------------------- /pictures/linux-fs/proc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/linux-fs/proc.png -------------------------------------------------------------------------------- /pictures/linux-fs/root.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/linux-fs/root.png -------------------------------------------------------------------------------- /pictures/linux-fs/sbin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/linux-fs/sbin.png -------------------------------------------------------------------------------- /pictures/linux-fs/tmp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/linux-fs/tmp.png -------------------------------------------------------------------------------- /pictures/linux-fs/usr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/linux-fs/usr.png -------------------------------------------------------------------------------- /pictures/linux-fs/usrbin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/linux-fs/usrbin.png -------------------------------------------------------------------------------- /pictures/linuxProcess/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/linuxProcess/1.jpg -------------------------------------------------------------------------------- /pictures/linuxProcess/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/linuxProcess/2.jpg -------------------------------------------------------------------------------- /pictures/linuxProcess/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/linuxProcess/3.jpg -------------------------------------------------------------------------------- /pictures/linuxProcess/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/linuxProcess/4.jpg -------------------------------------------------------------------------------- /pictures/linuxProcess/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/linuxProcess/5.jpg -------------------------------------------------------------------------------- /pictures/linuxProcess/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/linuxProcess/6.jpg -------------------------------------------------------------------------------- /pictures/linuxProcess/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/linuxProcess/7.jpg -------------------------------------------------------------------------------- /pictures/linuxProcess/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/linuxProcess/8.jpg -------------------------------------------------------------------------------- /pictures/linuxshell/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/linuxshell/1.png -------------------------------------------------------------------------------- /pictures/mergeInterval/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/mergeInterval/1.jpg -------------------------------------------------------------------------------- /pictures/mergeInterval/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/mergeInterval/2.jpg -------------------------------------------------------------------------------- /pictures/mergeInterval/3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/mergeInterval/3.gif -------------------------------------------------------------------------------- /pictures/mergeInterval/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/mergeInterval/title.png -------------------------------------------------------------------------------- /pictures/online/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/online/1.png -------------------------------------------------------------------------------- /pictures/online/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/online/10.png -------------------------------------------------------------------------------- /pictures/online/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/online/11.png -------------------------------------------------------------------------------- /pictures/online/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/online/2.png -------------------------------------------------------------------------------- /pictures/online/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/online/3.png -------------------------------------------------------------------------------- /pictures/online/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/online/4.png -------------------------------------------------------------------------------- /pictures/online/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/online/5.png -------------------------------------------------------------------------------- /pictures/online/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/online/6.png -------------------------------------------------------------------------------- /pictures/online/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/online/7.png -------------------------------------------------------------------------------- /pictures/online/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/online/8.png -------------------------------------------------------------------------------- /pictures/online/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/online/9.png -------------------------------------------------------------------------------- /pictures/others/leetcode.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/others/leetcode.jpeg -------------------------------------------------------------------------------- /pictures/pancakeSort/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/pancakeSort/1.jpg -------------------------------------------------------------------------------- /pictures/pancakeSort/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/pancakeSort/2.png -------------------------------------------------------------------------------- /pictures/pancakeSort/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/pancakeSort/3.jpg -------------------------------------------------------------------------------- /pictures/pancakeSort/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/pancakeSort/4.jpg -------------------------------------------------------------------------------- /pictures/pancakeSort/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/pancakeSort/title.png -------------------------------------------------------------------------------- /pictures/pay.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/pay.jpg -------------------------------------------------------------------------------- /pictures/plugin/chrome.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/plugin/chrome.gif -------------------------------------------------------------------------------- /pictures/plugin/chrome.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/plugin/chrome.jpg -------------------------------------------------------------------------------- /pictures/plugin/jetbrain.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/plugin/jetbrain.gif -------------------------------------------------------------------------------- /pictures/plugin/jetbrain.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/plugin/jetbrain.jpg -------------------------------------------------------------------------------- /pictures/plugin/vscode.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/plugin/vscode.gif -------------------------------------------------------------------------------- /pictures/plugin/vscode.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/plugin/vscode.jpg -------------------------------------------------------------------------------- /pictures/plugin/全家桶.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/plugin/全家桶.jpg -------------------------------------------------------------------------------- /pictures/prime/1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/prime/1.gif -------------------------------------------------------------------------------- /pictures/qrcode.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/qrcode.jpg -------------------------------------------------------------------------------- /pictures/redis入侵/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/redis入侵/1.png -------------------------------------------------------------------------------- /pictures/redis入侵/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/redis入侵/2.png -------------------------------------------------------------------------------- /pictures/redis入侵/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/redis入侵/3.png -------------------------------------------------------------------------------- /pictures/redis入侵/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/redis入侵/4.png -------------------------------------------------------------------------------- /pictures/redis入侵/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/redis入侵/5.png -------------------------------------------------------------------------------- /pictures/redis入侵/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/redis入侵/6.png -------------------------------------------------------------------------------- /pictures/robber/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/robber/1.jpg -------------------------------------------------------------------------------- /pictures/robber/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/robber/2.jpg -------------------------------------------------------------------------------- /pictures/robber/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/robber/3.jpg -------------------------------------------------------------------------------- /pictures/robber/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/robber/title.png -------------------------------------------------------------------------------- /pictures/robber/title1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/robber/title1.png -------------------------------------------------------------------------------- /pictures/session/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/session/1.png -------------------------------------------------------------------------------- /pictures/session/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/session/2.png -------------------------------------------------------------------------------- /pictures/session/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/session/3.png -------------------------------------------------------------------------------- /pictures/session/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/session/4.jpg -------------------------------------------------------------------------------- /pictures/souyisou.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/souyisou.png -------------------------------------------------------------------------------- /pictures/souyisou2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/souyisou2.png -------------------------------------------------------------------------------- /pictures/unionfind/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/unionfind/1.jpg -------------------------------------------------------------------------------- /pictures/unionfind/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/unionfind/2.jpg -------------------------------------------------------------------------------- /pictures/unionfind/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/unionfind/3.jpg -------------------------------------------------------------------------------- /pictures/unionfind/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/unionfind/4.jpg -------------------------------------------------------------------------------- /pictures/unionfind/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/unionfind/5.jpg -------------------------------------------------------------------------------- /pictures/unionfind/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/unionfind/6.jpg -------------------------------------------------------------------------------- /pictures/unionfind/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/unionfind/7.jpg -------------------------------------------------------------------------------- /pictures/unionfind/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/unionfind/8.jpg -------------------------------------------------------------------------------- /pictures/unionfind/9.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/unionfind/9.gif -------------------------------------------------------------------------------- /pictures/unionfind应用/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/unionfind应用/1.jpg -------------------------------------------------------------------------------- /pictures/unionfind应用/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/unionfind应用/2.jpg -------------------------------------------------------------------------------- /pictures/unionfind应用/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/unionfind应用/3.jpg -------------------------------------------------------------------------------- /pictures/youtube/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/youtube/1.png -------------------------------------------------------------------------------- /pictures/youtube/1573133096614.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/youtube/1573133096614.jpeg -------------------------------------------------------------------------------- /pictures/youtube/1573133131308.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/youtube/1573133131308.jpeg -------------------------------------------------------------------------------- /pictures/youtube/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/youtube/2.jpg -------------------------------------------------------------------------------- /pictures/youtube/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/youtube/3.jpg -------------------------------------------------------------------------------- /pictures/youtube/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/youtube/4.jpg -------------------------------------------------------------------------------- /pictures/二分应用/title1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/二分应用/title1.png -------------------------------------------------------------------------------- /pictures/二分应用/title2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/二分应用/title2.png -------------------------------------------------------------------------------- /pictures/二分查找/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/二分查找/1.jpg -------------------------------------------------------------------------------- /pictures/二分查找/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/二分查找/2.jpg -------------------------------------------------------------------------------- /pictures/二分查找/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/二分查找/3.jpg -------------------------------------------------------------------------------- /pictures/二分查找/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/二分查找/4.jpg -------------------------------------------------------------------------------- /pictures/二分查找/binarySearch1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/二分查找/binarySearch1.png -------------------------------------------------------------------------------- /pictures/二分查找/binarySearch2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/二分查找/binarySearch2.png -------------------------------------------------------------------------------- /pictures/二分查找/poem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/二分查找/poem.png -------------------------------------------------------------------------------- /pictures/位操作/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/位操作/1.png -------------------------------------------------------------------------------- /pictures/位操作/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/位操作/title.png -------------------------------------------------------------------------------- /pictures/信封嵌套/0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/信封嵌套/0.jpg -------------------------------------------------------------------------------- /pictures/信封嵌套/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/信封嵌套/1.jpg -------------------------------------------------------------------------------- /pictures/信封嵌套/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/信封嵌套/2.jpg -------------------------------------------------------------------------------- /pictures/信封嵌套/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/信封嵌套/title.png -------------------------------------------------------------------------------- /pictures/全家桶.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/全家桶.jpg -------------------------------------------------------------------------------- /pictures/前缀和/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/前缀和/1.jpg -------------------------------------------------------------------------------- /pictures/前缀和/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/前缀和/2.jpg -------------------------------------------------------------------------------- /pictures/前缀和/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/前缀和/title.png -------------------------------------------------------------------------------- /pictures/动态规划详解/coindp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/动态规划详解/coindp.png -------------------------------------------------------------------------------- /pictures/动态规划详解/coinfunc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/动态规划详解/coinfunc.png -------------------------------------------------------------------------------- /pictures/动态规划详解/cointree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/动态规划详解/cointree.png -------------------------------------------------------------------------------- /pictures/动态规划详解/fibdp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/动态规划详解/fibdp.png -------------------------------------------------------------------------------- /pictures/动态规划详解/fibfunc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/动态规划详解/fibfunc.png -------------------------------------------------------------------------------- /pictures/动态规划详解/fibmemo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/动态规划详解/fibmemo.png -------------------------------------------------------------------------------- /pictures/动态规划详解/fibtree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/动态规划详解/fibtree.png -------------------------------------------------------------------------------- /pictures/动态规划详解/img_20190514_013033.441.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/动态规划详解/img_20190514_013033.441.png -------------------------------------------------------------------------------- /pictures/动态规划详解/img_20190514_013830.397.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/动态规划详解/img_20190514_013830.397.png -------------------------------------------------------------------------------- /pictures/动态规划详解/ink-image (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/动态规划详解/ink-image (1).png -------------------------------------------------------------------------------- /pictures/动态规划详解/ink-image (2).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/动态规划详解/ink-image (2).png -------------------------------------------------------------------------------- /pictures/动态规划详解/ink-image (3).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/动态规划详解/ink-image (3).png -------------------------------------------------------------------------------- /pictures/动态规划详解/ink-image (4).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/动态规划详解/ink-image (4).png -------------------------------------------------------------------------------- /pictures/动态规划详解/ink-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/动态规划详解/ink-image.png -------------------------------------------------------------------------------- /pictures/动态规划详解进阶/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/动态规划详解进阶/1.jpg -------------------------------------------------------------------------------- /pictures/动态规划详解进阶/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/动态规划详解进阶/2.jpg -------------------------------------------------------------------------------- /pictures/动态规划详解进阶/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/动态规划详解进阶/3.jpg -------------------------------------------------------------------------------- /pictures/动态规划详解进阶/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/动态规划详解进阶/4.jpg -------------------------------------------------------------------------------- /pictures/动态规划详解进阶/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/动态规划详解进阶/5.jpg -------------------------------------------------------------------------------- /pictures/动态规划详解进阶/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/动态规划详解进阶/6.jpg -------------------------------------------------------------------------------- /pictures/动态规划详解进阶/coin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/动态规划详解进阶/coin.png -------------------------------------------------------------------------------- /pictures/动态规划详解进阶/fib.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/动态规划详解进阶/fib.png -------------------------------------------------------------------------------- /pictures/单调栈/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/单调栈/1.png -------------------------------------------------------------------------------- /pictures/单调栈/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/单调栈/2.png -------------------------------------------------------------------------------- /pictures/单调栈/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/单调栈/3.png -------------------------------------------------------------------------------- /pictures/单调队列/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/单调队列/1.png -------------------------------------------------------------------------------- /pictures/单调队列/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/单调队列/2.png -------------------------------------------------------------------------------- /pictures/单调队列/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/单调队列/3.png -------------------------------------------------------------------------------- /pictures/单调队列/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/单调队列/title.png -------------------------------------------------------------------------------- /pictures/博弈问题/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/博弈问题/1.png -------------------------------------------------------------------------------- /pictures/博弈问题/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/博弈问题/2.png -------------------------------------------------------------------------------- /pictures/博弈问题/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/博弈问题/3.png -------------------------------------------------------------------------------- /pictures/博弈问题/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/博弈问题/4.png -------------------------------------------------------------------------------- /pictures/双指针/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/双指针/1.png -------------------------------------------------------------------------------- /pictures/双指针/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/双指针/2.png -------------------------------------------------------------------------------- /pictures/双指针/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/双指针/3.png -------------------------------------------------------------------------------- /pictures/双指针/center.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/双指针/center.png -------------------------------------------------------------------------------- /pictures/双指针/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/双指针/title.png -------------------------------------------------------------------------------- /pictures/反转链表/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/反转链表/1.jpg -------------------------------------------------------------------------------- /pictures/反转链表/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/反转链表/2.jpg -------------------------------------------------------------------------------- /pictures/反转链表/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/反转链表/3.jpg -------------------------------------------------------------------------------- /pictures/反转链表/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/反转链表/4.jpg -------------------------------------------------------------------------------- /pictures/反转链表/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/反转链表/5.jpg -------------------------------------------------------------------------------- /pictures/反转链表/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/反转链表/6.jpg -------------------------------------------------------------------------------- /pictures/反转链表/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/反转链表/7.jpg -------------------------------------------------------------------------------- /pictures/反转链表/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/反转链表/title.png -------------------------------------------------------------------------------- /pictures/回文/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/回文/title.png -------------------------------------------------------------------------------- /pictures/回文链表/1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/回文链表/1.gif -------------------------------------------------------------------------------- /pictures/回文链表/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/回文链表/1.jpg -------------------------------------------------------------------------------- /pictures/回文链表/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/回文链表/2.jpg -------------------------------------------------------------------------------- /pictures/回文链表/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/回文链表/3.jpg -------------------------------------------------------------------------------- /pictures/回文链表/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/回文链表/4.jpg -------------------------------------------------------------------------------- /pictures/子序列/1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/子序列/1.gif -------------------------------------------------------------------------------- /pictures/子序列/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/子序列/1.jpg -------------------------------------------------------------------------------- /pictures/子序列/2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/子序列/2.gif -------------------------------------------------------------------------------- /pictures/子序列/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/子序列/2.jpg -------------------------------------------------------------------------------- /pictures/子序列/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/子序列/3.jpg -------------------------------------------------------------------------------- /pictures/子集/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/子集/1.jpg -------------------------------------------------------------------------------- /pictures/子集/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/子集/2.jpg -------------------------------------------------------------------------------- /pictures/子集/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/子集/3.jpg -------------------------------------------------------------------------------- /pictures/字符串乘法/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/字符串乘法/1.jpg -------------------------------------------------------------------------------- /pictures/字符串乘法/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/字符串乘法/2.jpg -------------------------------------------------------------------------------- /pictures/字符串乘法/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/字符串乘法/3.jpg -------------------------------------------------------------------------------- /pictures/字符串乘法/4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/字符串乘法/4.gif -------------------------------------------------------------------------------- /pictures/字符串乘法/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/字符串乘法/6.jpg -------------------------------------------------------------------------------- /pictures/字符串乘法/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/字符串乘法/title.png -------------------------------------------------------------------------------- /pictures/密码技术/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/密码技术/1.jpg -------------------------------------------------------------------------------- /pictures/密码技术/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/密码技术/2.jpg -------------------------------------------------------------------------------- /pictures/密码技术/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/密码技术/3.jpg -------------------------------------------------------------------------------- /pictures/密码技术/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/密码技术/4.jpg -------------------------------------------------------------------------------- /pictures/密码技术/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/密码技术/5.jpg -------------------------------------------------------------------------------- /pictures/密码技术/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/密码技术/6.jpg -------------------------------------------------------------------------------- /pictures/密码技术/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/密码技术/7.jpg -------------------------------------------------------------------------------- /pictures/座位调度/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/座位调度/1.jpg -------------------------------------------------------------------------------- /pictures/座位调度/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/座位调度/2.jpg -------------------------------------------------------------------------------- /pictures/座位调度/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/座位调度/3.jpg -------------------------------------------------------------------------------- /pictures/座位调度/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/座位调度/4.jpg -------------------------------------------------------------------------------- /pictures/座位调度/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/座位调度/5.jpg -------------------------------------------------------------------------------- /pictures/座位调度/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/座位调度/6.jpg -------------------------------------------------------------------------------- /pictures/座位调度/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/座位调度/7.jpg -------------------------------------------------------------------------------- /pictures/扔鸡蛋/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/扔鸡蛋/1.jpg -------------------------------------------------------------------------------- /pictures/扔鸡蛋/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/扔鸡蛋/2.jpg -------------------------------------------------------------------------------- /pictures/扔鸡蛋/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/扔鸡蛋/3.jpg -------------------------------------------------------------------------------- /pictures/扔鸡蛋/dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/扔鸡蛋/dp.png -------------------------------------------------------------------------------- /pictures/接雨水/0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/接雨水/0.jpg -------------------------------------------------------------------------------- /pictures/接雨水/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/接雨水/1.jpg -------------------------------------------------------------------------------- /pictures/接雨水/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/接雨水/2.jpg -------------------------------------------------------------------------------- /pictures/接雨水/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/接雨水/3.jpg -------------------------------------------------------------------------------- /pictures/接雨水/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/接雨水/4.jpg -------------------------------------------------------------------------------- /pictures/接雨水/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/接雨水/5.jpg -------------------------------------------------------------------------------- /pictures/接雨水/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/接雨水/title.png -------------------------------------------------------------------------------- /pictures/数组交换/ink-image (1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/数组交换/ink-image (1).png -------------------------------------------------------------------------------- /pictures/数组交换/ink-image (2).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/数组交换/ink-image (2).png -------------------------------------------------------------------------------- /pictures/数组交换/ink-image (3).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/数组交换/ink-image (3).png -------------------------------------------------------------------------------- /pictures/数组交换/ink-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/数组交换/ink-image.png -------------------------------------------------------------------------------- /pictures/最优子结构/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/最优子结构/1.jpg -------------------------------------------------------------------------------- /pictures/最长回文子序列/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/最长回文子序列/1.jpg -------------------------------------------------------------------------------- /pictures/最长回文子序列/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/最长回文子序列/2.jpg -------------------------------------------------------------------------------- /pictures/最长回文子序列/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/最长回文子序列/3.jpg -------------------------------------------------------------------------------- /pictures/最长回文子序列/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/最长回文子序列/4.jpg -------------------------------------------------------------------------------- /pictures/最长回文子序列/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/最长回文子序列/5.jpg -------------------------------------------------------------------------------- /pictures/最长递增子序列/1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/最长递增子序列/1.jpeg -------------------------------------------------------------------------------- /pictures/最长递增子序列/2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/最长递增子序列/2.jpeg -------------------------------------------------------------------------------- /pictures/最长递增子序列/3.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/最长递增子序列/3.jpeg -------------------------------------------------------------------------------- /pictures/最长递增子序列/gif1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/最长递增子序列/gif1.gif -------------------------------------------------------------------------------- /pictures/最长递增子序列/gif2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/最长递增子序列/gif2.gif -------------------------------------------------------------------------------- /pictures/最长递增子序列/poker1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/最长递增子序列/poker1.jpeg -------------------------------------------------------------------------------- /pictures/最长递增子序列/poker2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/最长递增子序列/poker2.jpeg -------------------------------------------------------------------------------- /pictures/最长递增子序列/poker3.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/最长递增子序列/poker3.jpeg -------------------------------------------------------------------------------- /pictures/最长递增子序列/poker4.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/最长递增子序列/poker4.jpeg -------------------------------------------------------------------------------- /pictures/最长递增子序列/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/最长递增子序列/title.png -------------------------------------------------------------------------------- /pictures/有序数组去重/1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/有序数组去重/1.gif -------------------------------------------------------------------------------- /pictures/有序数组去重/2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/有序数组去重/2.gif -------------------------------------------------------------------------------- /pictures/有序数组去重/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/有序数组去重/title.png -------------------------------------------------------------------------------- /pictures/栈队列/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/栈队列/1.jpg -------------------------------------------------------------------------------- /pictures/栈队列/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/栈队列/2.jpg -------------------------------------------------------------------------------- /pictures/栈队列/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/栈队列/3.jpg -------------------------------------------------------------------------------- /pictures/栈队列/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/栈队列/4.jpg -------------------------------------------------------------------------------- /pictures/栈队列/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/栈队列/5.jpg -------------------------------------------------------------------------------- /pictures/栈队列/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/栈队列/6.jpg -------------------------------------------------------------------------------- /pictures/概率问题/p.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/概率问题/p.png -------------------------------------------------------------------------------- /pictures/概率问题/sanmen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/概率问题/sanmen.png -------------------------------------------------------------------------------- /pictures/概率问题/tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/概率问题/tree.png -------------------------------------------------------------------------------- /pictures/正则/1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/正则/1.jpeg -------------------------------------------------------------------------------- /pictures/正则/2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/正则/2.jpeg -------------------------------------------------------------------------------- /pictures/正则/3.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/正则/3.jpeg -------------------------------------------------------------------------------- /pictures/正则/4.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/正则/4.jpeg -------------------------------------------------------------------------------- /pictures/正则/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/正则/example.png -------------------------------------------------------------------------------- /pictures/正则/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/正则/title.png -------------------------------------------------------------------------------- /pictures/洗牌算法/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/洗牌算法/1.png -------------------------------------------------------------------------------- /pictures/洗牌算法/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/洗牌算法/2.png -------------------------------------------------------------------------------- /pictures/洗牌算法/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/洗牌算法/3.png -------------------------------------------------------------------------------- /pictures/洗牌算法/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/洗牌算法/4.png -------------------------------------------------------------------------------- /pictures/洗牌算法/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/洗牌算法/5.jpg -------------------------------------------------------------------------------- /pictures/洗牌算法/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/洗牌算法/6.png -------------------------------------------------------------------------------- /pictures/滑动窗口/0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/滑动窗口/0.png -------------------------------------------------------------------------------- /pictures/滑动窗口/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/滑动窗口/1.png -------------------------------------------------------------------------------- /pictures/滑动窗口/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/滑动窗口/2.png -------------------------------------------------------------------------------- /pictures/滑动窗口/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/滑动窗口/3.png -------------------------------------------------------------------------------- /pictures/滑动窗口/title1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/滑动窗口/title1.png -------------------------------------------------------------------------------- /pictures/滑动窗口/title2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/滑动窗口/title2.png -------------------------------------------------------------------------------- /pictures/滑动窗口/title3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/滑动窗口/title3.png -------------------------------------------------------------------------------- /pictures/缺失元素/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/缺失元素/1.jpg -------------------------------------------------------------------------------- /pictures/缺失元素/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/缺失元素/2.jpg -------------------------------------------------------------------------------- /pictures/缺失元素/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/缺失元素/3.jpg -------------------------------------------------------------------------------- /pictures/缺失元素/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/缺失元素/title.png -------------------------------------------------------------------------------- /pictures/缺失元素/xor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/缺失元素/xor.png -------------------------------------------------------------------------------- /pictures/股票问题/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/股票问题/1.png -------------------------------------------------------------------------------- /pictures/股票问题/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/股票问题/title.png -------------------------------------------------------------------------------- /pictures/设计Twitter/design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/设计Twitter/design.png -------------------------------------------------------------------------------- /pictures/设计Twitter/merge.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/设计Twitter/merge.gif -------------------------------------------------------------------------------- /pictures/设计Twitter/tweet.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/设计Twitter/tweet.jpg -------------------------------------------------------------------------------- /pictures/设计Twitter/user.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/pictures/设计Twitter/user.jpg -------------------------------------------------------------------------------- /starHistory.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/starHistory.jpg -------------------------------------------------------------------------------- /starHistory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labuladong/fucking-algorithm/c5894e6c85f55a84a36932609edcc94cfd493a77/starHistory.png -------------------------------------------------------------------------------- /动态规划系列/README.md: -------------------------------------------------------------------------------- 1 | # 动态规划系列 2 | 3 | 我们公众号最火的就是动态规划系列的文章,也许是动态规划问题有难度而且有意思,也许因为它是面试常考题型。不管你之前是否害怕动态规划系列的问题,相信这一章的内容足以帮助你消除对动态规划算法的恐惧。 4 | 5 | 具体来说,动态规划的一般流程就是三步:**暴力的递归解法 -> 带备忘录的递归解法 -> 迭代的动态规划解法**。 6 | 7 | 就思考流程来说,就分为一下几步:**找到状态和选择 -> 明确 dp 数组/函数的定义 -> 寻找状态之间的关系**。 8 | 9 | 这就是思维模式的框架,**本章都会按照以上的模式来解决问题,辅助读者养成这种模式思维**,有了方向遇到问题就不会抓瞎,足以解决一般的动态规划问题。 10 | 11 | 欢迎关注我的公众号 labuladong,查看全部文章: 12 | 13 | ![labuladong二维码](../pictures/qrcode.jpg) -------------------------------------------------------------------------------- /动态规划系列/背包问题.md: -------------------------------------------------------------------------------- 1 | # 经典动态规划:0-1 背包问题 2 | 3 | 4 | 5 | ![](https://labuladong.online/algo/images/souyisou1.png) 6 | 7 | **通知:为满足广大读者的需求,网站上架 [速成目录](https://labuladong.online/algo/intro/quick-learning-plan/),如有需要可以看下,谢谢大家的支持~另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。** 8 | 9 | 10 | 11 | **-----------** 12 | 13 | 14 | 15 | > [!NOTE] 16 | > 阅读本文前,你需要先学习: 17 | > 18 | > - [动态规划核心框架](https://labuladong.online/algo/essential-technique/dynamic-programming-framework/) 19 | 20 | > tip:本文有视频版:[0-1背包问题详解](https://www.bilibili.com/video/BV15B4y1P7X7/)。建议关注我的 B 站账号,我会用视频领读的方式带大家学习那些稍有难度的算法技巧。 21 | 22 | 23 | 24 | 后台天天有人问背包问题,这个问题其实不难,借助动态规划的思维框架,无非还是状态 + 选择,没啥特别之处。今天就来说一下背包问题吧,就讨论最常见的 0-1 背包问题。描述: 25 | 26 | 给你一个可装载重量为 `W` 的背包和 `N` 个物品,每个物品有重量和价值两个属性。其中第 `i` 个物品的重量为 `wt[i]`,价值为 `val[i]`。现在让你用这个背包装物品,每个物品只能用一次,在不超过背包容量的前提下,最多能装的价值是多少? 27 | 28 | ![](https://labuladong.online/algo/images/knapsack/1.png) 29 | 30 | 举个简单的例子,输入如下: 31 | 32 | ```py 33 | N = 3, W = 4 34 | wt = [2, 1, 3] 35 | val = [4, 2, 3] 36 | ``` 37 | 38 | 算法返回 6,选择前两件物品装进背包,总重量 3 小于 `W`,可以获得最大价值 6。 39 | 40 | 题目就是这么简单,一个典型的动态规划问题。这个题目中的物品不可以分割,要么装进包里,要么不装,不能说切成两块装一半。这就是 0-1 背包这个名词的来历。 41 | 42 | 解决这个问题没有什么排序之类巧妙的方法,只能穷举所有可能,根据我们 [动态规划详解](https://labuladong.online/algo/essential-technique/dynamic-programming-framework/) 中的套路,直接走流程就行了。 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | ## 动规标准套路 51 | 52 | 看来每篇动态规划文章都得重复一遍套路,历史文章中的动态规划问题都是按照下面的套路来的。 53 | 54 | **第一步要明确两点,「状态」和「选择」**。 55 | 56 | 先说状态,如何才能描述一个问题局面?只要给几个物品和一个背包的容量限制,就形成了一个背包问题呀。**所以状态有两个,就是「背包的容量」和「可选择的物品」**。 57 | 58 | 再说选择,也很容易想到啊,对于每件物品,你能选择什么?**选择就是「装进背包」或者「不装进背包」嘛**。 59 | 60 | 明白了状态和选择,动态规划问题基本上就解决了,对于自底向上的思考方式,代码的一般框架是这样: 61 | 62 | ```python 63 | for 状态1 in 状态1的所有取值: 64 | for 状态2 in 状态2的所有取值: 65 | for ... 66 | dp[状态1][状态2][...] = 择优(选择1,选择2...) 67 | ``` 68 | 69 | **第二步要明确 `dp` 数组的定义**。 70 | 71 | 首先看看刚才找到的「状态」,有两个,也就是说我们需要一个二维 `dp` 数组。 72 | 73 | `dp[i][w]` 的定义如下:对于前 `i` 个物品,当前背包的容量为 `w`,这种情况下可以装的最大价值是 `dp[i][w]`。 74 | 75 | 比如说,如果 `dp[3][5] = 6`,其含义为:对于给定的一系列物品中,若只对前 3 个物品进行选择,当背包容量为 5 时,最多可以装下的价值为 6。 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | > [!NOTE] 84 | > 为什么要这么定义?因为这样可以找到状态转移关系,或者说这就是背包问题的特殊定义方式,你当做套路记下来就行,未来遇到动态规划相关问题,都可以这样定义试一试。 85 | 86 | 根据这个定义,我们想求的最终答案就是 `dp[N][W]`。base case 就是 `dp[0][..] = dp[..][0] = 0`,因为没有物品或者背包没有空间的时候,能装的最大价值就是 0。 87 | 88 | 细化上面的框架: 89 | 90 | ```python 91 | int[][] dp[N+1][W+1] 92 | dp[0][..] = 0 93 | dp[..][0] = 0 94 | 95 | for i in [1..N]: 96 | for w in [1..W]: 97 | dp[i][w] = max( 98 | 把物品 i 装进背包, 99 | 不把物品 i 装进背包 100 | ) 101 | return dp[N][W] 102 | ``` 103 | 104 | **第三步,根据「选择」,思考状态转移的逻辑**。 105 | 106 | 简单说就是,上面伪码中「把物品 `i` 装进背包」和「不把物品 `i` 装进背包」怎么用代码体现出来呢? 107 | 108 | 这就要结合对 `dp` 数组的定义,看看这两种选择会对状态产生什么影响: 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 先重申一下刚才我们的 `dp` 数组的定义: 117 | 118 | `dp[i][w]` 表示:对于前 `i` 个物品(从 1 开始计数),当前背包的容量为 `w` 时,这种情况下可以装下的最大价值是 `dp[i][w]`。 119 | 120 | **如果你没有把这第 `i` 个物品装入背包**,那么很显然,最大价值 `dp[i][w]` 应该等于 `dp[i-1][w]`,继承之前的结果。 121 | 122 | **如果你把这第 `i` 个物品装入了背包**,那么 `dp[i][w]` 应该等于 `val[i-1] + dp[i-1][w - wt[i-1]]`。 123 | 124 | 首先,由于数组索引从 0 开始,而我们定义中的 `i` 是从 1 开始计数的,所以 `val[i-1]` 和 `wt[i-1]` 表示第 `i` 个物品的价值和重量。 125 | 126 | 你如果选择将第 `i` 个物品装进背包,那么第 `i` 个物品的价值 `val[i-1]` 肯定就到手了,接下来你就要在剩余容量 `w - wt[i-1]` 的限制下,在前 `i - 1` 个物品中挑选,求最大价值,即 `dp[i-1][w - wt[i-1]]`。 127 | 128 | 综上就是两种选择,我们都已经分析完毕,也就是写出来了状态转移方程,可以进一步细化代码: 129 | 130 | ```python 131 | for i in [1..N]: 132 | for w in [1..W]: 133 | dp[i][w] = max( 134 | dp[i-1][w], 135 | dp[i-1][w - wt[i-1]] + val[i-1] 136 | ) 137 | return dp[N][W] 138 | ``` 139 | 140 | **最后一步,把伪码翻译成代码,处理一些边界情况**。 141 | 142 | 我用 Java 写的代码,把上面的思路完全翻译了一遍,并且处理了 `w - wt[i-1]` 可能小于 0 导致数组索引越界的问题: 143 | 144 | ```java 145 | int knapsack(int W, int N, int[] wt, int[] val) { 146 | assert N == wt.length; 147 | // base case 已初始化 148 | int[][] dp = new int[N + 1][W + 1]; 149 | for (int i = 1; i <= N; i++) { 150 | for (int w = 1; w <= W; w++) { 151 | if (w - wt[i - 1] < 0) { 152 | // 这种情况下只能选择不装入背包 153 | dp[i][w] = dp[i - 1][w]; 154 | } else { 155 | // 装入或者不装入背包,择优 156 | dp[i][w] = Math.max( 157 | dp[i - 1][w - wt[i-1]] + val[i-1], 158 | dp[i - 1][w] 159 | ); 160 | } 161 | } 162 | } 163 | 164 | return dp[N][W]; 165 | } 166 | ``` 167 | 168 | 169 |
170 | 171 |
172 | 173 | 👾 代码可视化动画👾 174 | 175 |
176 |
177 |
178 | 179 | 180 | 181 | > [!NOTE] 182 | > 其实函数签名中的物品数量 `N` 就是 `wt` 数组的长度,所以实际上这个参数 `N` 是多此一举的。但为了体现原汁原味的 0-1 背包问题,我就带上这个参数 `N` 了,你自己写的话可以省略。 183 | 184 | 至此,背包问题就解决了,相比而言,我觉得这是比较简单的动态规划问题,因为状态转移的推导比较自然,基本上你明确了 `dp` 数组的定义,就可以理所当然地确定状态转移了。 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 |
193 |
194 | 引用本文的文章 195 | 196 | - [扫描线技巧:安排会议室](https://labuladong.online/algo/frequency-interview/scan-line-technique/) 197 | - [经典动态规划:子集背包问题](https://labuladong.online/algo/dynamic-programming/knapsack2/) 198 | - [经典动态规划:完全背包问题](https://labuladong.online/algo/dynamic-programming/knapsack3/) 199 | - [背包问题的变体:目标和](https://labuladong.online/algo/dynamic-programming/target-sum/) 200 | 201 |

202 | 203 | 204 | 205 | 206 |
207 |
208 | 引用本文的题目 209 | 210 | 安装 [我的 Chrome 刷题插件](https://labuladong.online/algo/intro/chrome/) 点开下列题目可直接查看解题思路: 211 | 212 | | LeetCode | 力扣 | 难度 | 213 | | :----: | :----: | :----: | 214 | | [1235. Maximum Profit in Job Scheduling](https://leetcode.com/problems/maximum-profit-in-job-scheduling/?show=1) | [1235. 规划兼职工作](https://leetcode.cn/problems/maximum-profit-in-job-scheduling/?show=1) | 🔴 | 215 | 216 |
217 |
218 | 219 | 220 | 221 | **_____________** 222 | 223 | 224 | 225 | ![](https://labuladong.online/algo/images/souyisou2.png) -------------------------------------------------------------------------------- /动态规划系列/贪心算法之区间调度问题.md: -------------------------------------------------------------------------------- 1 | # 贪心算法之区间调度问题 2 | 3 | 4 | 5 | ![](https://labuladong.online/algo/images/souyisou1.png) 6 | 7 | **通知:为满足广大读者的需求,网站上架 [速成目录](https://labuladong.online/algo/intro/quick-learning-plan/),如有需要可以看下,谢谢大家的支持~另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。** 8 | 9 | 10 | 11 | 读完本文,你不仅学会了算法套路,还可以顺便解决如下题目: 12 | 13 | | LeetCode | 力扣 | 难度 | 14 | | :----: | :----: | :----: | 15 | | [435. Non-overlapping Intervals](https://leetcode.com/problems/non-overlapping-intervals/) | [435. 无重叠区间](https://leetcode.cn/problems/non-overlapping-intervals/) | 🟠 | 16 | | [452. Minimum Number of Arrows to Burst Balloons](https://leetcode.com/problems/minimum-number-of-arrows-to-burst-balloons/) | [452. 用最少数量的箭引爆气球](https://leetcode.cn/problems/minimum-number-of-arrows-to-burst-balloons/) | 🟠 | 17 | 18 | **-----------** 19 | 20 | 21 | 22 | 什么是贪心算法呢?贪心算法可以认为是动态规划算法的一个特例,相比动态规划,使用贪心算法需要满足更多的条件(贪心选择性质),但是效率比动态规划要高。 23 | 24 | 比如说一个算法问题使用暴力解法需要指数级时间,如果能使用动态规划消除重叠子问题,就可以降到多项式级别的时间,如果满足贪心选择性质,那么可以进一步降低时间复杂度,达到线性级别的。 25 | 26 | 什么是贪心选择性质呢,简单说就是:每一步都做出一个局部最优的选择,最终的结果就是全局最优。注意哦,这是一种特殊性质,其实只有一部分问题拥有这个性质。 27 | 28 | 比如你面前放着 100 张人民币,你只能拿十张,怎么才能拿最多的面额?显然每次选择剩下钞票中面值最大的一张,最后你的选择一定是最优的。 29 | 30 | 然而,大部分问题明显不具有贪心选择性质。比如打斗地主,对手出对儿三,按照贪心策略,你应该出尽可能小的牌刚好压制住对方,但现实情况我们甚至可能会出王炸。这种情况就不能用贪心算法,而得使用动态规划解决,参见前文 [动态规划解决博弈问题](https://labuladong.online/algo/dynamic-programming/game-theory/)。 31 | 32 | ## 一、问题概述 33 | 34 | 言归正传,本文解决一个很经典的贪心算法问题 Interval Scheduling(区间调度问题),也就是力扣第 435 题「无重叠区间」: 35 | 36 | 给你很多形如 `[start, end]` 的闭区间,请你设计一个算法,**算出这些区间中最多有几个互不相交的区间**。 37 | 38 | ```java 39 | int intervalSchedule(int[][] intvs); 40 | ``` 41 | 42 | 举个例子,`intvs = [[1,3], [2,4], [3,6]]`,这些区间最多有 2 个区间互不相交,即 `[[1,3], [3,6]]`,你的算法应该返回 2。注意边界相同并不算相交。 43 | 44 | 这个问题在生活中的应用广泛,比如你今天有好几个活动,每个活动都可以用区间 `[start, end]` 表示开始和结束的时间,请问你今天**最多能参加几个活动呢**?显然你一个人不能同时参加两个活动,所以说这个问题就是求这些时间区间的最大不相交子集。 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | ## 二、贪心解法 53 | 54 | 这个问题有许多看起来不错的贪心思路,却都不能得到正确答案。比如说: 55 | 56 | 也许我们可以每次选择可选区间中开始最早的那个?但是可能存在某些区间开始很早,但是很长,使得我们错误地错过了一些短的区间。或者我们每次选择可选区间中最短的那个?或者选择出现冲突最少的那个区间?这些方案都能很容易举出反例,不是正确的方案。 57 | 58 | 正确的思路其实很简单,可以分为以下三步: 59 | 60 | 1、从区间集合 `intvs` 中选择一个区间 `x`,这个 `x` 是在当前所有区间中**结束最早的**(`end` 最小)。 61 | 62 | 2、把所有与 `x` 区间相交的区间从区间集合 `intvs` 中删除。 63 | 64 | 3、重复步骤 1 和 2,直到 `intvs` 为空为止。之前选出的那些 `x` 就是最大不相交子集。 65 | 66 | 把这个思路实现成算法的话,可以按每个区间的 `end` 数值升序排序,因为这样处理之后实现步骤 1 和步骤 2 都方便很多,如下 GIF 所示: 67 | 68 | ![](https://labuladong.online/algo/images/interval/1.gif) 69 | 70 | 现在来实现算法,对于步骤 1,由于我们预先按照 `end` 排了序,所以选择 `x` 是很容易的。关键在于,如何去除与 `x` 相交的区间,选择下一轮循环的 `x` 呢? 71 | 72 | **由于我们事先排了序**,不难发现所有与 `x` 相交的区间必然会与 `x` 的 `end` 相交;如果一个区间不想与 `x` 的 `end` 相交,它的 `start` 必须要大于(或等于)`x` 的 `end`: 73 | 74 | ![](https://labuladong.online/algo/images/interval/2.jpg) 75 | 76 | 看下代码: 77 | 78 | ```java 79 | class Solution { 80 | public int intervalSchedule(int[][] intvs) { 81 | if (intvs.length == 0) return 0; 82 | // 按 end 升序排序 83 | Arrays.sort(intvs, (a, b) -> Integer.compare(a[1], b[1])); 84 | // 至少有一个区间不相交 85 | int count = 1; 86 | // 排序后,第一个区间就是 x 87 | int x_end = intvs[0][1]; 88 | for (int[] interval : intvs) { 89 | int start = interval[0]; 90 | if (start >= x_end) { 91 | // 找到下一个选择的区间了 92 | count++; 93 | x_end = interval[1]; 94 | } 95 | } 96 | return count; 97 | } 98 | } 99 | ``` 100 | 101 | ## 三、应用举例 102 | 103 | 下面再举例几道具体的题目应用一下区间调度算法。 104 | 105 | 首先是力扣第 435 题「无重叠区间」问题: 106 | 107 | 输入一个区间的集合,请你计算,要想使其中的区间都互不重叠,至少需要移除几个区间?函数签名如下: 108 | 109 | ```java 110 | int eraseOverlapIntervals(int[][] intvs); 111 | ``` 112 | 113 | 其中,可以假设输入的区间的终点总是大于起点,另外边界相等的区间只算接触,但并不算相互重叠。 114 | 115 | 比如说输入是 `intvs = [[1,2],[2,3],[3,4],[1,3]]`,算法返回 1,因为只要移除 `[1,3]` 后,剩下的区间就没有重叠了。 116 | 117 | 我们已经会求最多有几个区间不会重叠了,那么剩下的不就是至少需要去除的区间吗? 118 | 119 | ```java 120 | class Solution { 121 | public int eraseOverlapIntervals(int[][] intvs) { 122 | int n = intvs.length; 123 | return n - intervalSchedule(intvs); 124 | } 125 | 126 | private int intervalSchedule(int[][] intvs) { 127 | // 见上文 128 | } 129 | } 130 | ``` 131 | 132 | 133 |
134 | 135 |
136 | 137 | 🍭 代码可视化动画🍭 138 | 139 |
140 |
141 |
142 | 143 | 144 | 145 | 再说说力扣第 452 题「用最少的箭头射爆气球」,我来描述一下题目: 146 | 147 | 假设在二维平面上有很多圆形的气球,这些圆形投影到 x 轴上会形成一个个区间对吧。那么给你输入这些区间,你沿着 x 轴前进,可以垂直向上射箭,请问你至少要射几箭才能把这些气球全部射爆呢? 148 | 149 | 函数签名如下: 150 | 151 | ```java 152 | int findMinArrowShots(int[][] intvs); 153 | ``` 154 | 155 | 比如说输入为 `[[10,16],[2,8],[1,6],[7,12]]`,算法应该返回 2,因为我们可以在 `x` 为 6 的地方射一箭,射爆 `[2,8]` 和 `[1,6]` 两个气球,然后在 `x` 为 10,11 或 12 的地方射一箭,射爆 `[10,16]` 和 `[7,12]` 两个气球。 156 | 157 | 其实稍微思考一下,这个问题和区间调度算法一模一样!如果最多有 `n` 个不重叠的区间,那么就至少需要 `n` 个箭头穿透所有区间: 158 | 159 | ![](https://labuladong.online/algo/images/interval/3.jpg) 160 | 161 | 只是有一点不一样,在 `intervalSchedule` 算法中,如果两个区间的边界触碰,不算重叠;而按照这道题目的描述,箭头如果碰到气球的边界气球也会爆炸,所以说相当于区间的边界触碰也算重叠: 162 | 163 | ![](https://labuladong.online/algo/images/interval/4.jpg) 164 | 165 | 所以只要将之前的算法稍作修改,就是这道题目的答案: 166 | 167 | ```java 168 | class Solution { 169 | public int findMinArrowShots(int[][] intvs) { 170 | if (intvs.length == 0) return 0; 171 | Arrays.sort(intvs, (a, b) -> Integer.compare(a[1], b[1])); 172 | int count = 1; 173 | int x_end = intvs[0][1]; 174 | 175 | for (int[] interval : intvs) { 176 | int start = interval[0]; 177 | // 把 >= 改成 > 就行了 178 | if (start > x_end) { 179 | count++; 180 | x_end = interval[1]; 181 | } 182 | } 183 | return count; 184 | } 185 | } 186 | ``` 187 | 188 | 189 |
190 | 191 |
192 | 193 | 🌈 代码可视化动画🌈 194 | 195 |
196 |
197 |
198 | 199 | 200 | 201 |
202 |
203 | 引用本文的文章 204 | 205 | - [一个方法解决三道区间问题](https://labuladong.online/algo/practice-in-action/interval-problem-summary/) 206 | - [剪视频剪出一个贪心算法](https://labuladong.online/algo/frequency-interview/cut-video/) 207 | - [扫描线技巧:安排会议室](https://labuladong.online/algo/frequency-interview/scan-line-technique/) 208 | 209 |

210 | 211 | 212 | 213 | 214 | 215 | **_____________** 216 | 217 | 218 | 219 | ![](https://labuladong.online/algo/images/souyisou2.png) -------------------------------------------------------------------------------- /动态规划系列/魔塔.md: -------------------------------------------------------------------------------- 1 | # 动态规划帮我通关了《魔塔》 2 | 3 | 4 | 5 | ![](https://labuladong.online/algo/images/souyisou1.png) 6 | 7 | **通知:为满足广大读者的需求,网站上架 [速成目录](https://labuladong.online/algo/intro/quick-learning-plan/),如有需要可以看下,谢谢大家的支持~另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。** 8 | 9 | 10 | 11 | 读完本文,你不仅学会了算法套路,还可以顺便解决如下题目: 12 | 13 | | LeetCode | 力扣 | 难度 | 14 | | :----: | :----: | :----: | 15 | | [174. Dungeon Game](https://leetcode.com/problems/dungeon-game/) | [174. 地下城游戏](https://leetcode.cn/problems/dungeon-game/) | 🔴 | 16 | 17 | **-----------** 18 | 19 | 20 | 21 | > [!NOTE] 22 | > 阅读本文前,你需要先学习: 23 | > 24 | > - [动态规划核心框架](https://labuladong.online/algo/essential-technique/dynamic-programming-framework/) 25 | 26 | 「魔塔」是一款经典的地牢类游戏,碰怪物要掉血,吃血瓶能加血,你要收集钥匙,一层一层上楼,最后救出美丽的公主。 27 | 28 | 现在手机上仍然可以玩这个游戏: 29 | 30 | ![](https://labuladong.online/algo/images/dungeons/0.png) 31 | 32 | 嗯,相信这款游戏承包了不少人的童年回忆,记得小时候,一个人拿着游戏机玩,两三个人围在左右指手画脚,这导致玩游戏的人体验极差,而左右的人异常快乐 😂 33 | 34 | 力扣第 174 题「地下城游戏」是一道类似的题目: 35 | 36 | 37 | 38 | **简单说,就是问你至少需要多少初始生命值,能够让骑士从最左上角移动到最右下角,且任何时候生命值都要大于 0**。 39 | 40 | 函数签名如下: 41 | 42 | ```java 43 | int calculateMinimumHP(int[][] grid); 44 | ``` 45 | 46 | 上篇文章 [最小路径和](https://labuladong.online/algo/dynamic-programming/minimum-path-sum/) 写过类似的问题,问你从左上角到右下角的最小路径和是多少。 47 | 48 | 我们做算法题一定要尝试举一反三,感觉今天这道题和最小路径和有点关系对吧? 49 | 50 | 想要最小化骑士的初始生命值,是不是意味着要最大化骑士行进路线上的血瓶?是不是相当于求「最大路径和」?是不是可以直接套用计算「最小路径和」的思路? 51 | 52 | 但是稍加思考,发现这个推论并不成立,吃到最多的血瓶,并不一定就能获得最小的初始生命值。 53 | 54 | 比如如下这种情况,如果想要吃到最多的血瓶获得「最大路径和」,应该按照下图箭头所示的路径,初始生命值需要 11: 55 | 56 | ![](https://labuladong.online/algo/images/dungeons/2.png) 57 | 58 | 但也很容易看到,正确的答案应该是下图箭头所示的路径,初始生命值只需要 1: 59 | 60 | ![](https://labuladong.online/algo/images/dungeons/3.png) 61 | 62 | **所以,关键不在于吃最多的血瓶,而是在于如何损失最少的生命值**。 63 | 64 | 这类求最值的问题,肯定要借助动态规划技巧,要合理设计 `dp` 数组/函数的定义。类比前文 [最小路径和问题](https://labuladong.online/algo/dynamic-programming/minimum-path-sum/),`dp` 函数签名肯定长这样: 65 | 66 | ```java 67 | int dp(int[][] grid, int i, int j); 68 | ``` 69 | 70 | 但是这道题对 `dp` 函数的定义比较有意思,按照常理,这个 `dp` 函数的定义应该是: 71 | 72 | **从左上角(`grid[0][0]`)走到 `grid[i][j]` 至少需要 `dp(grid, i, j)` 的生命值**。 73 | 74 | 这样定义的话,base case 就是 `i, j` 都等于 0 的时候,我们可以这样写代码: 75 | 76 | ```java 77 | int calculateMinimumHP(int[][] grid) { 78 | int m = grid.length; 79 | int n = grid[0].length; 80 | // 我们想计算左上角到右下角所需的最小生命值 81 | return dp(grid, m - 1, n - 1); 82 | } 83 | 84 | int dp(int[][] grid, int i, int j) { 85 | // base case 86 | if (i == 0 && j == 0) { 87 | // 保证骑士落地不死就行了 88 | return grid[i][j] > 0 ? 1 : -grid[i][j] + 1; 89 | } 90 | ... 91 | } 92 | ``` 93 | 94 | > [!NOTE] 95 | > 为了简洁,之后 `dp(grid, i, j)` 就简写为 `dp(i, j)`,大家理解就好。 96 | 97 | 接下来我们需要找状态转移了,还记得如何找状态转移方程吗?我们这样定义 `dp` 函数能否正确进行状态转移呢? 98 | 99 | 我们希望 `dp(i, j)` 能够通过 `dp(i-1, j)` 和 `dp(i, j-1)` 推导出来,这样就能不断逼近 base case,也就能够正确进行状态转移。 100 | 101 | 具体来说,「到达 `A` 的最小生命值」应该能够由「到达 `B` 的最小生命值」和「到达 `C` 的最小生命值」推导出来: 102 | 103 | ![](https://labuladong.online/algo/images/dungeons/4.png) 104 | 105 | **但问题是,能推出来么?实际上是不能的**。 106 | 107 | 因为按照 `dp` 函数的定义,你只知道「能够从左上角到达 `B` 的最小生命值」,但并不知道「到达 `B` 时的生命值」。 108 | 109 | 「到达 `B` 时的生命值」是进行状态转移的必要参考,我给你举个例子你就明白了,假设下图这种情况: 110 | 111 | ![](https://labuladong.online/algo/images/dungeons/5.png) 112 | 113 | 你说这种情况下,骑士救公主的最优路线是什么? 114 | 115 | 显然是按照图中蓝色的线走到 `B`,最后走到 `A` 对吧,这样初始血量只需要 1 就可以;如果走黄色箭头这条路,先走到 `C` 然后走到 `A`,初始血量至少需要 6。 116 | 117 | 为什么会这样呢?骑士走到 `B` 和 `C` 的最少初始血量都是 1,为什么最后是从 `B` 走到 `A`,而不是从 `C` 走到 `A` 呢? 118 | 119 | 因为骑士走到 `B` 的时候生命值为 11,而走到 `C` 的时候生命值依然是 1。 120 | 121 | 如果骑士执意要通过 `C` 走到 `A`,那么初始血量必须加到 6 点才行;而如果通过 `B` 走到 `A`,初始血量为 1 就够了,因为路上吃到血瓶了,生命值足够抗 `A` 上面怪物的伤害。 122 | 123 | 这下应该说的很清楚了,再回顾我们对 `dp` 函数的定义,上图的情况,算法只知道 `dp(1, 2) = dp(2, 1) = 1`,都是一样的,怎么做出正确的决策,计算出 `dp(2, 2)` 呢? 124 | 125 | **所以说,我们之前对 `dp` 数组的定义是错误的,信息量不足,算法无法做出正确的状态转移**。 126 | 127 | 正确的做法需要反向思考,依然是如下的 `dp` 函数: 128 | 129 | ```java 130 | int dp(int[][] grid, int i, int j); 131 | ``` 132 | 133 | 但是我们要修改 `dp` 函数的定义: 134 | 135 | **从 `grid[i][j]` 到达终点(右下角)所需的最少生命值是 `dp(grid, i, j)`**。 136 | 137 | 那么可以这样写代码: 138 | 139 | ```java 140 | int calculateMinimumHP(int[][] grid) { 141 | // 我们想计算左上角到右下角所需的最小生命值 142 | return dp(grid, 0, 0); 143 | } 144 | 145 | int dp(int[][] grid, int i, int j) { 146 | int m = grid.length; 147 | int n = grid[0].length; 148 | // base case 149 | if (i == m - 1 && j == n - 1) { 150 | return grid[i][j] >= 0 ? 1 : -grid[i][j] + 1; 151 | } 152 | ... 153 | } 154 | ``` 155 | 156 | 根据新的 `dp` 函数定义和 base case,我们想求 `dp(0, 0)`,那就应该试图通过 `dp(i, j+1)` 和 `dp(i+1, j)` 推导出 `dp(i, j)`,这样才能不断逼近 base case,正确进行状态转移。 157 | 158 | 具体来说,「从 `A` 到达右下角的最少生命值」应该由「从 `B` 到达右下角的最少生命值」和「从 `C` 到达右下角的最少生命值」推导出来: 159 | 160 | ![](https://labuladong.online/algo/images/dungeons/6.png) 161 | 162 | 能不能推导出来呢?这次是可以的,假设 `dp(0, 1) = 5, dp(1, 0) = 4`,那么可以肯定要从 `A` 走向 `C`,因为 4 小于 5 嘛。 163 | 164 | 那么怎么推出 `dp(0, 0)` 是多少呢? 165 | 166 | 假设 `A` 的值为 1,既然知道下一步要往 `C` 走,且 `dp(1, 0) = 4` 意味着走到 `grid[1][0]` 的时候至少要有 4 点生命值,那么就可以确定骑士出现在 `A` 点时需要 4 - 1 = 3 点初始生命值,对吧。 167 | 168 | 那如果 `A` 的值为 10,落地就能捡到一个大血瓶,超出了后续需求,4 - 10 = -6 意味着骑士的初始生命值为负数,这显然不可以,骑士的生命值小于 1 就挂了,所以这种情况下骑士的初始生命值应该是 1。 169 | 170 | 综上,状态转移方程已经推出来了: 171 | 172 | 173 | 174 | 175 | 176 | ```java 177 | int res = min( 178 | dp(i + 1, j), 179 | dp(i, j + 1) 180 | ) - grid[i][j]; 181 | 182 | dp(i, j) = res <= 0 ? 1 : res; 183 | ``` 184 | 185 | 根据这个核心逻辑,加一个备忘录消除重叠子问题,就可以直接写出最终的代码了: 186 | 187 | ```java 188 | class Solution { 189 | // 主函数 190 | public int calculateMinimumHP(int[][] grid) { 191 | int m = grid.length; 192 | int n = grid[0].length; 193 | // 备忘录中都初始化为 -1 194 | memo = new int[m][n]; 195 | for (int[] row : memo) { 196 | Arrays.fill(row, -1); 197 | } 198 | 199 | return dp(grid, 0, 0); 200 | } 201 | 202 | // 备忘录,消除重叠子问题 203 | int[][] memo; 204 | 205 | // 定义:从 (i, j) 到达右下角,需要的初始血量至少是多少 206 | int dp(int[][] grid, int i, int j) { 207 | int m = grid.length; 208 | int n = grid[0].length; 209 | // base case 210 | if (i == m - 1 && j == n - 1) { 211 | return grid[i][j] >= 0 ? 1 : -grid[i][j] + 1; 212 | } 213 | if (i == m || j == n) { 214 | return Integer.MAX_VALUE; 215 | } 216 | // 避免重复计算 217 | if (memo[i][j] != -1) { 218 | return memo[i][j]; 219 | } 220 | // 状态转移逻辑 221 | int res = Math.min( 222 | dp(grid, i, j + 1), 223 | dp(grid, i + 1, j) 224 | ) - grid[i][j]; 225 | // 骑士的生命值至少为 1 226 | memo[i][j] = res <= 0 ? 1 : res; 227 | 228 | return memo[i][j]; 229 | } 230 | } 231 | ``` 232 | 233 | 234 |
235 | 236 |
237 | 238 | 👾 代码可视化动画👾 239 | 240 |
241 |
242 |
243 | 244 | 245 | 246 | 这就是自顶向下带备忘录的动态规划解法,参考前文 [动态规划套路详解](https://labuladong.online/algo/essential-technique/dynamic-programming-framework/) 很容易就可以改写成 `dp` 数组的迭代解法,这里就不写了,读者可以尝试自己写一写。 247 | 248 | 这道题的核心是定义 `dp` 函数,找到正确的状态转移方程,从而计算出正确的答案。 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | **_____________** 259 | 260 | 261 | 262 | ![](https://labuladong.online/algo/images/souyisou2.png) -------------------------------------------------------------------------------- /多语言解法代码/contribution-guide.md: -------------------------------------------------------------------------------- 1 | # 修正 labuladong 刷题插件中的错误 2 | 3 | ## 背景 4 | 5 | 为了帮助大家更好地学习算法,我之前写了很多算法教程,并开发了一系列刷题插件,统称为《labuladong 的刷题全家桶》,详情见 [这里](https://labuladong.github.io/article/fname.html?fname=全家桶简介)。 6 | 7 | 在我的教程和插件中的解法主要使用的是 Java 语言,原因是 Java 这门语言中规中矩,就算之前没有接触过,也能比较容易看懂逻辑。不过现在这不是 chatGPT 横空出世了嘛,我就借助 chatGPT 把我的解法改写成多种语言,希望对不同技术背景的小伙伴更加友好。 8 | 9 | chatGPT 的改写效果还是非常不错的,不过难免还是存在一些错误,所以我希望能够和大家一起来修正这些错误。 10 | 11 | ## 如何反馈错误 12 | 13 | 如果你发现某些解法代码不能通过力扣的所有测试用例(一般都是 chatGPT 改写的解法代码会出现这种情况,我的解法代码都是通过测试才发布的),可以 [点这里](https://github.com/labuladong/fucking-algorithm/issues/new?assignees=&labels=code+bug&template=bug_report.yml&title=%5Bbug%5D%5B%7B%E8%BF%99%E9%87%8C%E6%9B%BF%E6%8D%A2%E4%B8%BA%E5%87%BA%E9%94%99%E7%9A%84%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80%7D%5D+%7B%E8%BF%99%E9%87%8C%E6%9B%BF%E6%8D%A2%E4%B8%BA%E5%87%BA%E9%94%99%E7%9A%84%E5%8A%9B%E6%89%A3%E9%A2%98%E7%9B%AE%E6%A0%87%E8%AF%86%E7%AC%A6%7D+) 按照模板提交 issue,我和其他小伙伴会提交 PR 修复这些错误。 14 | 15 | ## 如何修正错误 16 | 17 | 首先,感谢你愿意为我的插件提供的解法代码纠错,你向本仓库提交 PR 修复错误后,你将成为本仓库的 contributor,出现在仓库首页的贡献者列表中。本仓库已经获得了 115k star,你的贡献将会被许多人看到。 18 | 19 | 修复代码很简单,所有多语言解法代码都存储在 [多语言解法代码/solution_code.md](https://github.com/labuladong/fucking-algorithm/blob/master/%E5%A4%9A%E8%AF%AD%E8%A8%80%E8%A7%A3%E6%B3%95%E4%BB%A3%E7%A0%81/solution_code.md) 中,你只要修改这个文件就行了。其内容的组织形如如下: 20 | 21 | 22 | https://leetcode.cn/problems/xxx 的多语言解法👇 23 | 24 | ```cpp 25 | class Solution { 26 | public: 27 | int xxx() { 28 | // ... 29 | } 30 | }; 31 | ``` 32 | 33 | ```java 34 | class Solution { 35 | public int xxx() { 36 | // ... 37 | } 38 | } 39 | ``` 40 | 41 | ```python 42 | class Solution: 43 | def xxx(self): 44 | # ... 45 | ``` 46 | 47 | ```javascript 48 | var xxx = function() { 49 | // ... 50 | } 51 | ``` 52 | 53 | ```go 54 | func xxx() { 55 | // ... 56 | } 57 | ``` 58 | 59 | https://leetcode.cn/problems/xxx 的多语言解法👆 60 | 61 | 62 | 比如你想修改 [https://leetcode-cn.com/problems/longest-palindromic-substring/](https://leetcode-cn.com/problems/longest-palindromic-substring/) 的 JavaScript 解法,你可以在 [多语言解法代码/solution_code.md](https://github.com/labuladong/fucking-algorithm/blob/master/%E5%A4%9A%E8%AF%AD%E8%A8%80%E8%A7%A3%E6%B3%95%E4%BB%A3%E7%A0%81/solution_code.md) 中搜索 `longest-palindromic-substring` 关键词,即可找到这道题的多语言解法,然后修改 JavaScript 对应的解法代码,提交 PR 即可。 63 | 64 | 我的插件会自动拉取这个文件的最新内容,所以你的 PR 被合进 master 分支后,插件中的内容修改也会生效。 65 | 66 | ## 提交 PR 的要求 67 | 68 | 1、你的 PR 必须是针对 [多语言解法代码/solution_code.md](https://github.com/labuladong/fucking-algorithm/blob/master/%E5%A4%9A%E8%AF%AD%E8%A8%80%E8%A7%A3%E6%B3%95%E4%BB%A3%E7%A0%81/solution_code.md) 文件中代码部分的修改,不要修改其他文件和其他内容。 69 | 70 | 2、把我的解法翻译成多语言的目的是帮助不同背景的小伙伴理解算法思维,所以你修改的代码可以不是效率最优的,但应该尽可能和我的解法思路保持一致,且包含我的解法中的完整注释。 71 | 72 | 3、你的 PR 描述中需要包含代码通过所有测试用例截图。PR 标题的格式为 `[fix][{lang}] {slug}`,其中 `{lang}` 需要替换为你修复的解法语言,比如 `[fix][cpp]`,`{slug}` 需要替换为你修复的题目的标识符(题目 URL 的最后一部分),比如 [https://leetcode.cn/problems/search-a-2d-matrix/](https://leetcode.cn/problems/search-a-2d-matrix/) 这道题的标识符就是 `search-a-2d-matrix`。 73 | 74 | **你可以查看这个 PR 作为案例**:https://github.com/labuladong/fucking-algorithm/pull/1112 -------------------------------------------------------------------------------- /技术/linux进程.md: -------------------------------------------------------------------------------- 1 | # Linux的进程、线程、文件描述符是什么 2 | 3 | 4 | 5 | ![](https://labuladong.online/algo/images/souyisou1.png) 6 | 7 | **通知:为满足广大读者的需求,网站上架 [速成目录](https://labuladong.online/algo/intro/quick-learning-plan/),如有需要可以看下,谢谢大家的支持~另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。** 8 | 9 | 10 | 11 | **-----------** 12 | 13 | 说到进程,恐怕面试中最常见的问题就是线程和进程的关系了,那么先说一下答案:**在 Linux 系统中,进程和线程几乎没有区别**。 14 | 15 | Linux 中的进程就是一个数据结构,看明白就可以理解文件描述符、重定向、管道命令的底层工作原理,最后我们从操作系统的角度看看为什么说线程和进程基本没有区别。 16 | 17 | ### 一、进程是什么 18 | 19 | 首先,抽象地来说,我们的计算机就是这个东西: 20 | 21 | ![](https://labuladong.online/algo/images/linuxProcess/1.jpg) 22 | 23 | 这个大的矩形表示计算机的**内存空间**,其中的小矩形代表**进程**,左下角的圆形表示**磁盘**,右下角的图形表示一些**输入输出设备**,比如鼠标键盘显示器等等。另外,注意到内存空间被划分为了两块,上半部分表示**用户空间**,下半部分表示**内核空间**。 24 | 25 | 用户空间装着用户进程需要使用的资源,比如你在程序代码里开一个数组,这个数组肯定存在用户空间;内核空间存放内核进程需要加载的系统资源,这一些资源一般是不允许用户访问的。但是注意有的用户进程会共享一些内核空间的资源,比如一些动态链接库等等。 26 | 27 | 我们用 C 语言写一个 hello 程序,编译后得到一个可执行文件,在命令行运行就可以打印出一句 hello world,然后程序退出。在操作系统层面,就是新建了一个进程,这个进程将我们编译出来的可执行文件读入内存空间,然后执行,最后退出。 28 | 29 | **你编译好的那个可执行程序只是一个文件**,不是进程,可执行文件必须要载入内存,包装成一个进程才能真正跑起来。进程是要依靠操作系统创建的,每个进程都有它的固有属性,比如进程号(PID)、进程状态、打开的文件等等,进程创建好之后,读入你的程序,你的程序才被系统执行。 30 | 31 | 那么,操作系统是如何创建进程的呢?**对于操作系统,进程就是一个数据结构**,我们直接来看 Linux 的源码: 32 | 33 | ```cpp 34 | struct task_struct { 35 | // 进程状态 36 | long state; 37 | // 虚拟内存结构体 38 | struct mm_struct *mm; 39 | // 进程号 40 | pid_t pid; 41 | // 指向父进程的指针 42 | struct task_struct __rcu *parent; 43 | // 子进程列表 44 | struct list_head children; 45 | // 存放文件系统信息的指针 46 | struct fs_struct *fs; 47 | // 一个数组,包含该进程打开的文件指针 48 | struct files_struct *files; 49 | }; 50 | ``` 51 | 52 | `task_struct` 就是 Linux 内核对于一个进程的描述,也可以称为「进程描述符」。源码比较复杂,我这里就截取了一小部分比较常见的。 53 | 54 | 其中比较有意思的是 `mm` 指针和 `files` 指针。`mm` 指向的是进程的虚拟内存,也就是载入资源和可执行文件的地方;`files` 指针指向一个数组,这个数组里装着所有该进程打开的文件的指针。 55 | 56 | ### 二、文件描述符是什么 57 | 58 | 先说 `files`,它是一个文件指针数组。一般来说,一个进程会从 `files[0]` 读取输入,将输出写入 `files[1]`,将错误信息写入 `files[2]`。 59 | 60 | 举个例子,以我们的角度 C 语言的 `printf` 函数是向命令行打印字符,但是从进程的角度来看,就是向 `files[1]` 写入数据;同理,`scanf` 函数就是进程试图从 `files[0]` 这个文件中读取数据。 61 | 62 | **每个进程被创建时,`files` 的前三位被填入默认值,分别指向标准输入流、标准输出流、标准错误流。我们常说的「文件描述符」就是指这个文件指针数组的索引**,所以程序的文件描述符默认情况下 0 是输入,1 是输出,2 是错误。 63 | 64 | 我们可以重新画一幅图: 65 | 66 | ![](https://labuladong.online/algo/images/linuxProcess/2.jpg) 67 | 68 | 对于一般的计算机,输入流是键盘,输出流是显示器,错误流也是显示器,所以现在这个进程和内核连了三根线。因为硬件都是由内核管理的,我们的进程需要通过「系统调用」让内核进程访问硬件资源。 69 | 70 | > [!NOTE] 71 | > 不要忘了,Linux 中一切都被抽象成文件,设备也是文件,可以进行读和写。 72 | 73 | 如果我们写的程序需要其他资源,比如打开一个文件进行读写,这也很简单,进行系统调用,让内核把文件打开,这个文件就会被放到 `files` 的第 4 个位置: 74 | 75 | ![](https://labuladong.online/algo/images/linuxProcess/3.jpg) 76 | 77 | 明白了这个原理,**输入重定向**就很好理解了,程序想读取数据的时候就会去 `files[0]` 读取,所以我们只要把 `files[0]` 指向一个文件,那么程序就会从这个文件中读取数据,而不是从键盘: 78 | 79 | ```shell 80 | $ command < file.txt 81 | ``` 82 | 83 | ![](https://labuladong.online/algo/images/linuxProcess/5.jpg) 84 | 85 | 同理,**输出重定向**就是把 `files[1]` 指向一个文件,那么程序的输出就不会写入到显示器,而是写入到这个文件中: 86 | 87 | ```shell 88 | $ command > file.txt 89 | ``` 90 | 91 | ![](https://labuladong.online/algo/images/linuxProcess/4.jpg) 92 | 93 | 错误重定向也是一样的,就不再赘述。 94 | 95 | **管道符**其实也是异曲同工,把一个进程的输出流和另一个进程的输入流接起一条「管道」,数据就在其中传递,不得不说这种设计思想真的很优美: 96 | 97 | ```shell 98 | $ cmd1 | cmd2 | cmd3 99 | ``` 100 | 101 | ![](https://labuladong.online/algo/images/linuxProcess/6.jpg) 102 | 103 | 到这里,你可能也看出「Linux 中一切皆文件」设计思路的高明了,不管是设备、另一个进程、socket 套接字还是真正的文件,全部都可以读写,统一装进一个简单的 `files` 数组,进程通过简单的文件描述符访问相应资源,具体细节交于操作系统,有效解耦,优美高效。 104 | 105 | ### 三、线程是什么 106 | 107 | 首先要明确的是,多进程和多线程都是并发,都可以提高处理器的利用效率,所以现在的关键是,多线程和多进程有啥区别。 108 | 109 | 为什么说 Linux 中线程和进程基本没有区别呢,因为从 Linux 内核的角度来看,并没有把线程和进程区别对待。 110 | 111 | 我们知道系统调用 `fork()` 可以新建一个子进程,函数 `pthread()` 可以新建一个线程。**但无论线程还是进程,都是用 `task_struct` 结构表示的,唯一的区别就是共享的数据区域不同**。 112 | 113 | 换句话说,线程看起来跟进程没有区别,只是线程的某些数据区域和其父进程是共享的,而子进程是拷贝副本,而不是共享。就比如说,`mm` 结构和 `files` 结构在线程中都是共享的,我画两张图你就明白了: 114 | 115 | ![](https://labuladong.online/algo/images/linuxProcess/7.jpg) 116 | 117 | ![](https://labuladong.online/algo/images/linuxProcess/8.jpg) 118 | 119 | 所以说,我们的多线程程序要利用锁机制,避免多个线程同时往同一区域写入数据,否则可能造成数据错乱。 120 | 121 | 那么你可能问,**既然进程和线程差不多,而且多进程数据不共享,即不存在数据错乱的问题,为什么多线程的使用比多进程普遍得多呢**? 122 | 123 | 因为现实中数据共享的并发更普遍呀,比如十个人同时从一个账户取十元,我们希望的是这个共享账户的余额正确减少一百元,而不是希望每人获得一个账户的拷贝,每个拷贝账户减少十元。 124 | 125 | 当然,必须要说明的是,只有 Linux 系统将线程看做共享数据的进程,不对其做特殊看待,其他的很多操作系统是对线程和进程区别对待的,线程有其特有的数据结构,我个人认为不如 Linux 的这种设计简洁,增加了系统的复杂度。 126 | 127 | 在 Linux 中新建线程和进程的效率都是很高的,对于新建进程时内存区域拷贝的问题,Linux 采用了 copy-on-write 的策略优化,也就是并不真正复制父进程的内存空间,而是等到需要写操作时才去复制。**所以 Linux 中新建进程和新建线程都是很迅速的**。 128 | 129 | 130 | 131 |
132 |
133 | 引用本文的文章 134 | 135 | - [Linux 管道符的坑](https://labuladong.online/algo/fname.html?fname=linux技巧3) 136 | - [关于 Linux shell 你必须知道的技巧](https://labuladong.online/algo/fname.html?fname=linuxshell) 137 | 138 |

139 | 140 | 141 | 142 | 143 | 144 | **_____________** 145 | 146 | 147 | 148 | ![](https://labuladong.online/algo/images/souyisou2.png) -------------------------------------------------------------------------------- /技术/redis入侵.md: -------------------------------------------------------------------------------- 1 | # Redis 入侵 2 | 3 | 4 | 5 | ![](https://labuladong.online/algo/images/souyisou1.png) 6 | 7 | **通知:为满足广大读者的需求,网站上架 [速成目录](https://labuladong.online/algo/intro/quick-learning-plan/),如有需要可以看下,谢谢大家的支持~另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。** 8 | 9 | 10 | 11 | **-----------** 12 | 13 | 好吧,我也做了回标题党,像我这么细心的同学,怎么可能让服务器被入侵呢? 14 | 15 | 其实是这样的,昨天我和一个朋友聊天,他说他自己有一台云服务器运行了 Redis 数据库,有一天突然发现数据库里的**数据全没了**,只剩下一个奇奇怪怪的键值对,其中值看起来像一个 RSA 公钥的字符串,他以为是误操作删库了,幸好自己的服务器里没啥重要的数据,也就没在意。 16 | 17 | 经过一番攀谈交心了解到,他跑了一个比较古老已经停止维护的开源项目,安装的旧版本的 Redis,而且他对 Linux 的使用不是很熟练。我就知道,他的服务器已经被攻陷了,想到也许还会有不少像我这位朋友的人,不重视操作系统的权限、防火墙的设置和数据库的保护,我就写一篇文章简单看看这种情况出现的原因,以及如何防范。 18 | 19 | > [!NOTE] 20 | > 这种手法现在已经行不通了,因为新版本 Redis 都增加了 protect mode,增加了安全性,我们只能在本地简单模拟一下,就别乱试了。 21 | 22 | ### 事件经过 23 | 24 | 其实这种攻击手法都是 2015 年的事了,那时候 Redis 的安全保护机制比较差,只能靠运维人员来合理配置以保证数据库的安全。有段时间,全球几万个 Redis 节点遭到了攻击,出现了上述奇怪的现象,所有数据被清空,只剩一个键叫 `crackit`,它的值形似 RSA 公钥的字符串。 25 | 26 | 后来查证,攻击者利用 Redis 动态设置配置和数据持久化的功能,把自己的 RSA 公钥写入到了被攻击服务器的 `/root/.ssh/authored_keys` 这个文件,从而可以用私钥直接登录对方的 root 用户,侵入对方系统。 27 | 28 | 沦陷的服务器安全防护做的很不好,具体如下: 29 | 30 | 1、Redis 的端口是默认端口,而且可以从公网访问。 31 | 32 | 2、Redis 还没设密码。 33 | 34 | 3、Redis 进程是由 root 用户启动的。 35 | 36 | 以上每个点都是比较危险的,合在一起,那真是很致命了。且不说别人把公钥写到你的系统里,就说连上你的数据库然后删库,那损失都够大了。那么具体的流程是什么呢,下面我在本地回环地址上简单演示一下。 37 | 38 | ### 本地演示 39 | 40 | Redis 监听的默认端口是 6379,我们设置它接收网卡 127.0.0.1 的连接,这样我从本地肯定可以连接 Redis,以此模拟「从公网可以访问 Redis」这一条件。 41 | 42 | 现在我是名叫 fdl 的普通用户,我想用 ssh 登录我系统上的 root 用户,要输入 root 的密码,我不知道,所以没办法登录。 43 | 44 | 除了密码登录之外,还可以使用 RSA 密钥对登录,但是必须要把我的公钥存到 root 的家目录中 `/root/.ssh/authored_keys`。我们知道 `/root` 目录的权限设置是不允许任何其他用户闯入读写的: 45 | 46 | ![](https://labuladong.online/algo/images/redis/1.png) 47 | 48 | 但是,我发现自己竟然可以直接访问 Redis: 49 | 50 | ![](https://labuladong.online/algo/images/redis/2.png) 51 | 52 | 如果 Redis 是以 root 的身份运行的,那么我就可以通过操作 Redis,让它把我的公钥写到 root 的家目录中。Redis 有一种持久化方式是生成 RDB 文件,其中会包含原始数据。 53 | 54 | 我露出了邪恶的微笑,先把 Redis 中的数据全部清空,然后把我的 RSA 公钥写到数据库里,这里在开头和结尾加换行符目的是避免 RDB 文件生成过程中损坏到公钥字符串: 55 | 56 | ![](https://labuladong.online/algo/images/redis/3.png) 57 | 58 | 命令 Redis 把生成的数据文件保存到 `/root/.ssh/` 中的 `authored_keys` 文件中: 59 | 60 | ![](https://labuladong.online/algo/images/redis/4.png) 61 | 62 | 现在,root 的家目录中已经包含了我们的 RSA 公钥,我们现在可以通过密钥对登录进 root 了: 63 | 64 | ![](https://labuladong.online/algo/images/redis/5.png) 65 | 66 | 看一下刚才写入 root 家的公钥: 67 | 68 | ![](https://labuladong.online/algo/images/redis/6.png) 69 | 70 | 乱码是 GDB 文件的某种编码吧,但是中间的公钥被完整保存了,而且 ssh 登录程序竟然也识别了这段被乱码包围的公钥! 71 | 72 | 至此,拥有了 root 权限,就可以为所欲为了。。。 73 | 74 | ### 吸取教训 75 | 76 | 虽然现在基本不会受到这种攻击(新版本的 Redis 没有密码时默认不对外网开放),但是对于系统的安全性是每个人都应该重视的。 77 | 78 | 我们自己折腾东西,用个低配云服务器,为了省事儿一般也不认真配置防火墙,数据库不设密码或者设成 admin、root 这样简单的密码,反正也没啥数据。这样肯定不是个好习惯。 79 | 80 | 现在我们的计算机系统越来越完善,每个成熟的项目都由最优秀的一帮人维护,从技术上说应该算是无懈可击了,那么唯一可能出问题的地方就在于使用它们的人。 81 | 82 | 就像经常看到有人的 QQ 被盗,我相信盗号的人肯定不是跑到腾讯的数据库里盗号,肯定是 QQ 号主安全防范意识差,在哪个钓鱼网站输入了自己的账号密码,导致被盗。我基本没见过微信被盗的,可能是微信弱化密码登录,改用二维码扫描登录的原因。这应该也算是一种安全方面的考量吧,毕竟微信是有支付功能的。 83 | 84 | 上面这种骗局对于技术人来说,看看 url,浏览器分析一下网络包就很容易识别出来,但是你还别不信,一般人真的搞不明白怎么识别钓鱼网站和官方网站。就像我真没想到都 2020 年了,还有人在找 Redis 的这个漏洞,而且还有人中招。。。 85 | 86 | 那么说回 Redis 数据库的使用,在官网上明确写出了安全防护的建议,我简单总结一下吧: 87 | 88 | 1、不要用 root 用户启动 Redis Server,而且一定要设置密码,而且密码不要太短,否则容易被暴力破解。 89 | 90 | 2、配置服务器防火墙和 Redis 的 config 文件,尽量不要让 Redis 与外界接触。 91 | 92 | 3、利用 rename 功能伪装 flushall 这种危险命令,以防被删库,丢失数据。 93 | 94 | 95 | 96 | 97 | 98 | **_____________** 99 | 100 | 101 | 102 | ![](https://labuladong.online/algo/images/souyisou2.png) -------------------------------------------------------------------------------- /技术/session和cookie.md: -------------------------------------------------------------------------------- 1 | # 一文读懂 session 和 cookie 2 | 3 | 4 | 5 | ![](https://labuladong.online/algo/images/souyisou1.png) 6 | 7 | **通知:为满足广大读者的需求,网站上架 [速成目录](https://labuladong.online/algo/intro/quick-learning-plan/),如有需要可以看下,谢谢大家的支持~另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。** 8 | 9 | 10 | 11 | **-----------** 12 | 13 | cookie 大家应该都熟悉,比如说登录某些网站一段时间后,就要求你重新登录;再比如有的同学很喜欢玩爬虫技术,有时候网站就是可以拦截住你的爬虫,这些都和 cookie 有关。如果你明白了服务器后端对于 cookie 和 session 的处理逻辑,就可以解释这些现象,甚至钻一些空子无限白嫖,待我慢慢道来。 14 | 15 | ### 一、session 和 cookie 简介 16 | 17 | cookie 的出现是因为 HTTP 是无状态的一种协议,换句话说,服务器记不住你,可能你每刷新一次网页,就要重新输入一次账号密码进行登录。这显然是让人无法接受的,cookie 的作用就好比服务器给你贴个标签,然后你每次向服务器再发请求时,服务器就能够 cookie 认出你。 18 | 19 | 抽象地概括一下:**一个 cookie 可以认为是一个「变量」,形如 `name=value`,存储在浏览器;一个 session 可以理解为一种数据结构,多数情况是「映射」(键值对),存储在服务器上**。 20 | 21 | 注意,我说的是「一个」cookie 可以认为是一个变量,但是服务器可以一次设置多个 cookie,所以有时候说 cookie 是「一组」键值对儿,这也可以说得通。 22 | 23 | cookie 可以在服务器端通过 HTTP 的 SetCookie 字段设置 cookie,比如我用 Go 语言写的一个简单服务: 24 | 25 | ```go 26 | func cookie(w http.ResponseWriter, r *http.Request) { 27 | // 设置了两个 cookie 28 | http.SetCookie(w, &http.Cookie{ 29 | Name: "name1", 30 | Value: "value1", 31 | }) 32 | 33 | http.SetCookie(w, &http.Cookie{ 34 | Name: "name2", 35 | Value: "value2", 36 | }) 37 | // 将字符串写入网页 38 | fmt.Fprintln(w, "页面内容") 39 | } 40 | ``` 41 | 42 | 当浏览器访问对应网址时,通过浏览器的开发者工具查看此次 HTTP 通信的细节,可以看见服务器的回应发出了两次 `SetCookie` 命令: 43 | 44 | ![](https://labuladong.online/algo/images/session/1.png) 45 | 46 | 在这之后,浏览器的请求中的 `Cookie` 字段就带上了这两个 cookie: 47 | 48 | ![](https://labuladong.online/algo/images/session/2.png) 49 | 50 | **cookie 的作用其实就是这么简单,无非就是服务器给每个客户端(浏览器)打的标签**,方便服务器辨认而已。当然,HTTP 还有很多参数可以设置 cookie,比如过期时间,或者让某个 cookie 只有某个特定路径才能使用等等。 51 | 52 | 但问题是,我们也知道现在的很多网站功能很复杂,而且涉及很多的数据交互,比如说电商网站的购物车功能,信息量大,而且结构也比较复杂,无法通过简单的 cookie 机制传递这么多信息,而且要知道 cookie 字段是存储在 HTTP header 中的,就算能够承载这些信息,也会消耗很多的带宽,比较消耗网络资源。 53 | 54 | session 就可以配合 cookie 解决这一问题,比如说一个 cookie 存储这样一个变量 `sessionID=xxxx`,仅仅把这一个 cookie 传给服务器,然后服务器通过这个 ID 找到对应的 session,这个 session 是一个数据结构,里面存储着该用户的购物车等详细信息,服务器可以通过这些信息返回该用户的定制化网页,有效解决了追踪用户的问题。 55 | 56 | **session 是一个数据结构,由网站的开发者设计,所以可以承载各种数据**,只要客户端的 cookie 传来一个唯一的 session ID,服务器就可以找到对应的 session,认出这个客户。 57 | 58 | 当然,由于 session 存储在服务器中,肯定会消耗服务器的资源,所以 session 一般都会有一个过期时间,服务器一般会定期检查并删除过期的 session,如果后来该用户再次访问服务器,可能就会面临重新登录等等措施,然后服务器新建一个 session,将 session ID 通过 cookie 的形式传送给客户端。 59 | 60 | 那么,我们知道 cookie 和 session 的原理,有什么切实的好处呢?**除了应对面试,我给你说一个鸡贼的用处,就是可以白嫖某些服务**。 61 | 62 | 有些网站,你第一次使用它的服务,它直接免费让你试用,但是用一次之后,就让你登录然后付费继续使用该服务。而且你发现网站似乎通过某些手段记住了你的电脑,除非你换个电脑或者换个浏览器才能再白嫖一次。 63 | 64 | 那么问题来了,你试用的时候没有登录,网站服务器是怎么记住你的呢?这就很显然了,服务器一定是给你的浏览器打了 cookie,后台建立了对应的 session 记录你的状态。你的浏览器在每次访问该网站的时候都会听话地带着 cookie,服务器一查 session 就知道这个浏览器已经免费使用过了,得让它登录付费,不能让它继续白嫖了。 65 | 66 | 那如果我不让浏览器发送 cookie,每次都伪装成一个第一次来试用的小萌新,不就可以不断白嫖了么?浏览器会把网站的 cookie 以文件的形式存在某些地方(不同的浏览器配置不同),你把他们找到然后删除就行了。但是对于 Firefox 和 Chrome 浏览器,有很多插件可以直接编辑 cookie,比如我的 Chrome 浏览器就用的一款叫做 EditThisCookie 的插件,这是他们官网: 67 | 68 | ![](https://labuladong.online/algo/images/session/3.png) 69 | 70 | 这类插件可以读取浏览器在当前网页的 cookie,点开插件可以任意编辑和删除 cookie。**当然,偶尔白嫖一两次还行,不鼓励高频率白嫖,想常用还是掏钱吧,否则网站赚不到钱,就只能取消免费试用这个机制了**。 71 | 72 | 以上就是关于 cookie 和 session 的简单介绍,cookie 是 HTTP 协议的一部分,不算复杂,而 session 是可以定制的,所以下面详细看一下实现 session 管理的代码架构吧。 73 | 74 | ### 二、session 的实现 75 | 76 | session 的原理不难,但是具体实现它可是很有技巧的,一般需要三个组件配合完成,它们分别是 `Manager`、`Provider` 和 `Session` 三个类(接口)。 77 | 78 | ![](https://labuladong.online/algo/images/session/4.jpg) 79 | 80 | 1、浏览器通过 HTTP 协议向服务器请求路径 `/content` 的网页资源,对应路径上有一个 Handler 函数接收请求,解析 HTTP header 中的 cookie,得到其中存储的 sessionID,然后把这个 ID 发给 `Manager`。 81 | 82 | 2、`Manager` 充当一个 session 管理器的角色,主要存储一些配置信息,比如 session 的存活时间,cookie 的名字等等。而所有的 session 存在 `Manager` 内部的一个 `Provider` 中。所以 `Manager` 会把 `sid`(sessionID)传递给 `Provider`,让它去找这个 ID 对应的具体是哪个 session。 83 | 84 | 3、`Provider` 就是一个容器,最常见的应该就是一个散列表,将每个 `sid` 和对应的 session 一一映射起来。收到 `Manager` 传递的 `sid` 之后,它就找到 `sid` 对应的 session 结构,也就是 `Session` 结构,然后返回它。 85 | 86 | 4、`Session` 中存储着用户的具体信息,由 Handler 函数中的逻辑拿出这些信息,生成该用户的 HTML 网页,返回给客户端。 87 | 88 | 那么你也许会问,为什么搞这么麻烦,直接在 Handler 函数中搞一个哈希表,然后存储 `sid` 和 `Session` 结构的映射不就完事儿了? 89 | 90 | **这就是设计层面的技巧了**,下面就来说说,为什么分成 `Manager`、`Provider` 和 `Session`。 91 | 92 | 先从最底层的 `Session` 说。既然 session 就是键值对,为啥不直接用哈希表,而是要抽象出这么一个数据结构呢? 93 | 94 | 第一,因为 `Session` 结构可能不止存储了一个哈希表,还可以存储一些辅助数据,比如 `sid`,访问次数,过期时间或者最后一次的访问时间,这样便于实现想 LRU、LFU 这样的算法。 95 | 96 | 第二,因为 session 可以有不同的存储方式。如果用编程语言内置的哈希表,那么 session 数据就是存储在内存中,如果数据量大,很容易造成程序崩溃,而且一旦程序结束,所有 session 数据都会丢失。所以可以有很多种 session 的存储方式,比如存入缓存数据库 Redis,或者存入 MySQL 等等。 97 | 98 | 因此,`Session` 结构提供一层抽象,屏蔽不同存储方式的差异,只要提供一组通用接口操纵键值对: 99 | 100 | ```go 101 | type Session interface { 102 | // 设置键值对 103 | Set(key, val interface{}) 104 | // 获取 key 对应的值 105 | Get(key interface{}) interface{} 106 | // 删除键 key 107 | Delete(key interface{}) 108 | } 109 | ``` 110 | 111 | 再说 `Provider` 为啥要抽象出来。我们上面那个图的 `Provider` 就是一个散列表,保存 `sid` 到 `Session` 的映射,但是实际中肯定会更加复杂。我们不是要时不时删除一些 session 吗,除了设置存活时间之外,还可以采用一些其他策略,比如 LRU 缓存淘汰算法,这样就需要 `Provider` 内部使用哈希链表这种数据结构来存储 session。 112 | 113 | > [!TIP] 114 | > 关于 LRU 算法的奥妙,参见前文 [LRU 算法详解](https://labuladong.online/algo/data-structure/lru-cache/)。 115 | 116 | 因此,`Provider` 作为一个容器,就是要屏蔽算法细节,以合理的数据结构和算法组织 `sid` 和 `Session` 的映射关系,只需要实现下面这几个方法实现对 session 的增删查改: 117 | 118 | ```go 119 | type Provider interface { 120 | // 新增并返回一个 session 121 | SessionCreate(sid string) (Session, error) 122 | // 删除一个 session 123 | SessionDestroy(sid string) 124 | // 查找一个 session 125 | SessionRead(sid string) (Session, error) 126 | // 修改一个session 127 | SessionUpdate(sid string) 128 | // 通过类似 LRU 的算法回收过期的 session 129 | SessionGC(maxLifeTime int64) 130 | } 131 | ``` 132 | 133 | 最后说 `Manager`,大部分具体工作都委托给 `Session` 和 `Provider` 承担了,`Manager` 主要就是一个参数集合,比如 session 的存活时间,清理过期 session 的策略,以及 session 的可用存储方式。`Manager` 屏蔽了操作的具体细节,我们可以通过 `Manager` 灵活地配置 session 机制。 134 | 135 | 综上,session 机制分成几部分的最主要原因就是解耦,实现定制化。我在 Github 上看过几个 Go 语言实现的 session 服务,源码都很简单,有兴趣的朋友可以学习学习: 136 | 137 | https://github.com/alexedwards/scs 138 | 139 | https://github.com/astaxie/build-web-application-with-golang 140 | 141 | 142 | 143 | 144 | 145 | **_____________** 146 | 147 | 148 | 149 | ![](https://labuladong.online/algo/images/souyisou2.png) -------------------------------------------------------------------------------- /技术/在线练习平台.md: -------------------------------------------------------------------------------- 1 | # 在线刷题学习平台 2 | 3 | 4 | 5 | ![](https://labuladong.online/algo/images/souyisou1.png) 6 | 7 | **通知:为满足广大读者的需求,网站上架 [速成目录](https://labuladong.online/algo/intro/quick-learning-plan/),如有需要可以看下,谢谢大家的支持~另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。** 8 | 9 | 10 | 11 | **-----------** 12 | 13 | 虽说我没事就喜欢喷应试教育,但我也从应试教育中发现了一个窍门:如果能够以刷题的形式学习某项技能,效率和效果是最佳的。对于技术的学习,我经常面临的困境是,**理论知识知道的不少,但是有的场景实在无法模拟,缺少亲自动手实践的机会**,如果能有一本带标准答案的习题册让我刷刷就好了。 14 | 15 | 所以在学习新技术时,我首先会去搜索是否有在线刷题平台,你还别说,有的大神真就做了很不错的在线练习平台,下面就介绍几个平台,分别是学习 Git、SQL、正则表达式的在线练习平台。 16 | 17 | ### 一、练习 Git 18 | 19 | 这是个叫做 Learning Git Branching 的项目,是我一定要推荐的: 20 | 21 | ![](https://labuladong.online/algo/images/online/1.png) 22 | 23 | 正如对话框中的自我介绍,这确实也是我至今发现的**最好**的 Git 动画教程,没有之一。 24 | 25 | 想当年我用 Git 就会 `add .`,`clone`,`push`,`pull`,`commit` 几个命令,其他的命令完全不会,Git 就是一个下载器,Github 就是个资源网站加免费图床,命令能不能达成目的都是靠运气。什么版本控制,我根本搞不懂,也懒得去看那一堆乱七八糟的文档。 26 | 27 | 这个网站的教程不是给你举那种修改文件的细节例子,而是将每次 `commit` 都抽象成树的节点,**用动画闯关的形式**,让你自由使用 Git 命令完成目标: 28 | 29 | ![](https://labuladong.online/algo/images/online/2.png) 30 | 31 | 所有 Git 分支都被可视化了,你只要在左侧的命令行输入 Git 命令,分支会进行相应的变化,只要达成任务目标,你就过关啦!网站还会记录你的命令数,试试能不能以最少的命令数过关! 32 | 33 | ![](https://labuladong.online/algo/images/online/3.png) 34 | 35 | 我一开始以为这个教程只包含本地 Git 仓库的版本管理,**后来我惊奇地发现它还有远程仓库的操作教程**! 36 | 37 | ![](https://labuladong.online/algo/images/online/4.png) 38 | 39 | ![](https://labuladong.online/algo/images/online/5.png) 40 | 41 | 真的跟玩游戏一样,难度设计合理,流畅度很好,我一玩都停不下来了,几小时就打通了,哈哈哈! 42 | 43 | ![](https://labuladong.online/algo/images/online/6.png) 44 | 45 | 总之,这个教程很适合初学和进阶,如果你觉得自己对 Git 的掌握还不太好,用 Git 命令还是靠碰运气,就可以玩玩这个教程,相信能够让你更熟练地使用 Git。 46 | 47 | 它是一个开源项目,Github 项目地址: 48 | 49 | https://github.com/pcottle/learnGitBranching 50 | 51 | 教程网站地址: 52 | 53 | https://learngitbranching.js.org 54 | 55 | ### 二、练习正则表达式 56 | 57 | **正则表达式是个非常强有力的工具**,可以说计算机中的一切数据都是字符,借助正则表达式这种模式匹配工具,操作计算机可以说是如虎添翼。 58 | 59 | 我这里要推荐两个网站,一个是练习平台,一个是测试正则表达式的平台。 60 | 61 | 先说练习平台,叫做 RegexOne: 62 | 63 | ![](https://labuladong.online/algo/images/online/9.png) 64 | 65 | 前面有基本教程,后面有一些常见的正则表达式题目,比如判断邮箱、URL、电话号,或者抽取日志的关键信息等等。 66 | 67 | 只要写出符合要求的正则表达式,就可以进入下一个问题,关键是每道题还有标准答案,可以点击下面的 solution 按钮查看: 68 | 69 | ![](https://labuladong.online/algo/images/online/10.png) 70 | 71 | RegexOne 网址: 72 | 73 | https://regexone.com/ 74 | 75 | 再说测试工具,是个叫做 RegExr 的 Github 项目,这是它的网站: 76 | 77 | ![](https://labuladong.online/algo/images/online/11.png) 78 | 79 | 可以看见,输入文本和正则模式串后,**网站会给正则表达式添加好看且容易辨认的样式,自动在文本中搜索模式串,高亮显示匹配的字符串,并且还会显示每个分组捕获的字符串**。 80 | 81 | 这个网站可以配合前面的正则练习平台使用,在这里尝试各种表达式,成功匹配之后粘贴过去。 82 | 83 | RegExr 网址: 84 | 85 | https://regexr.com/ 86 | 87 | ### 三、练习 SQL 88 | 89 | 这是一个叫做 SQLZOO 的网站,左侧是所有的练习内容: 90 | 91 | ![](https://labuladong.online/algo/images/online/7.png) 92 | 93 | SQLZOO 是一款很好用的 SQL 练习平台,英文不难理解,可以直接看英文版,但是也可以切换繁体中文,比较友好。 94 | 95 | 这里都是比较常用的 SQL 命令,给你一个需求,你写 SQL 语句实现正确的查询结果。**最重要的是,这里不仅对每个命令的用法有详细解释,每个专题后面还有选择题(quiz),而且有判题系统,甚至有的比较难的题目还有视频讲解**: 96 | 97 | ![](https://labuladong.online/algo/images/online/8.png) 98 | 99 | 至于难度,循序渐进,即便对新手也很友好,靠后的问题确实比较有技巧性,相信这是热爱思维挑战的人喜欢的!LeetCode 也有 SQL 相关的题目,不过难度一般比较大,我觉得 SQLZOO 刷完基础 SQL 命令再去 LeetCode 刷比较合适。 100 | 101 | 网站地址: 102 | 103 | https://sqlzoo.net/ 104 | 105 | 106 | 107 |
108 |
109 | 引用本文的文章 110 | 111 | - [四个基本命令搞会 Git 使用](https://labuladong.online/algo/fname.html?fname=git常用命令) 112 | 113 |

114 | 115 | 116 | 117 | 118 | 119 | **_____________** 120 | 121 | 122 | 123 | ![](https://labuladong.online/algo/images/souyisou2.png) -------------------------------------------------------------------------------- /技术/密码技术.md: -------------------------------------------------------------------------------- 1 | # 密码算法的前世今生 2 | 3 | 4 | 5 | ![](https://labuladong.online/algo/images/souyisou1.png) 6 | 7 | **通知:为满足广大读者的需求,网站上架 [速成目录](https://labuladong.online/algo/intro/quick-learning-plan/),如有需要可以看下,谢谢大家的支持~另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。** 8 | 9 | 10 | 11 | **-----------** 12 | 13 | 说到密码,我们第一个想到的就是登陆账户的密码,但是从密码学的角度来看,这种根本就不算合格的密码。 14 | 15 | 为什么呢,因为我们的账户密码,是依靠隐蔽性来达到加密作用:密码藏在我心里,你不知道,所以你登不上我的账户。 16 | 17 | 然而密码技术认为,「保密」信息总有一天会被扒出来,所以加密算法不应该依靠「保密」来保证机密性,而应该做到:即便知道了加密算法,依然无计可施。说的魔幻一点就是,告诉你我的密码,你依然不知道我的密码。 18 | 19 | 最玄学的就是 Diffie-Hellman 密钥交换算法,我当初就觉得很惊奇,两个人当着你的面互相报几个数字,他们就可以拥有一个共同的秘密,而你却根本不可能算出来这个秘密。下文会着重介绍一下这个算法。 20 | 21 | 本文讨论的密码技术要解决的主要是信息传输中的加密和解密问题。要假设数据传输过程是不安全的,所有信息都在被窃听的,所以发送端要把信息加密,接收方收到信息之后,肯定得知道如何解密。有意思的是,如果你能够让接收者知道如何解密,那么窃听者不是也能够知道如何解密了吗? 22 | 23 | 下面,**我们会介绍对称加密算法、密钥交换算法、非对称加密算法、数字签名、公钥证书**,看看解决安全传输问题的一路坎坷波折。 24 | 25 | ### 一、对称性加密 26 | 27 | 对称性密码,也叫共享密钥密码,顾名思义,这种加密方式用相同的密钥进行加密和解密。 28 | 29 | 比如我说一种最简单的对称加密的方法。首先我们知道信息都可以表示成 0/1 比特序列,也知道相同的两个比特序列做异或运算的结果为 0。 30 | 31 | 那么我们就可以生成一个长度和原始信息一样的随机比特序列作为密钥,然后用它对原始信息做异或运算,就生成了密文。反之,再用该密钥对密文做一次异或运算,就可以恢复原始信息。 32 | 33 | 这是一个简单例子,不过有些过于简单,有很多问题。比如密钥的长度和原始信息完全一致,如果原始信息很大,密钥也会一样大,而且生成大量真随机比特序列的计算开销也比较大。 34 | 35 | 当然,有很多更复杂优秀的对称加密算法解决了这些问题,比如 Rijndael 算法、三重 DES 算法等等。**它们从算法上是无懈可击的,也就是拥有巨大的密钥空间,基本无法暴力破解,而且加密过程相对快速**。 36 | 37 | **但是,一切对称加密算法的软肋在于密钥的配送**。加密和解密用同一个密钥,发送方必须设法把密钥发送给接收方。如果窃听者有能力窃取密文,肯定也可以窃取密钥,那么再无懈可击的算法依然不攻自破。 38 | 39 | 所以,下面介绍两种解决密钥配送问题最常见的算法,分别是 Diffie-Hellman 密钥交换算法和非对称加密算法。 40 | 41 | ### 二、密钥交换算法 42 | 43 | 我们所说的密钥一般就是一个很大的数字,算法用这个数加密、解密。问题在于,信道是不安全的,所有发出的数据都会被窃取。换句话说,有没有一种办法,能够让两个人在众目睽睽之下,光明正大地交换一个秘密,把对称性密钥安全地送到接收方的手中? 44 | 45 | Diffie-Hellman 密钥交换算法可以做到。**准确的说,该算法并不是把一个秘密安全地「送给」对方,而是通过一些共享的数字,双方「心中」各自「生成」了一个相同的秘密,而且双方的这个秘密,是第三方窃听者无法生成的**。 46 | 47 | 也许这就是传说中的心有灵犀一点通吧。 48 | 49 | 这个算法规则不算复杂,你甚至都可以找个朋友尝试一下共享秘密,等会我会简单画出它的基本流程。在此之前,需要明确一个问题:**并不是所有运算都有逆运算**。 50 | 51 | 最简单的例子就是我们熟知的单向散列函数,给一个数字 `a` 和一个散列函数 `f`,你可以很快计算出 `f(a)`,但是如果给你 `f(a)` 和 `f`,推出 `a` 是一件基本做不到的事。密钥交换算法之所以看起来如此玄幻,就是利用了这种不可逆的性质。 52 | 53 | 下面,看下密钥交换算法的流程是什么,按照命名惯例,准备执行密钥交换算法的双方称为 Alice 和 Bob,在网络中企图窃取他俩通信内容的坏人称为 Hack 吧。 54 | 55 | 首先,Alice 和 Bob 协商出两个数字 `N` 和 `G` 作为生成元,当然协商过程可以被窃听者 Hack 窃取,所以我把这两个数画到中间,代表三方都知道: 56 | 57 | ![](https://labuladong.online/algo/images/cryptography/1.jpg) 58 | 59 | 现在 Alice 和 Bob **心中**各自想一个数字出来,分别称为 `A` 和 `B` 吧: 60 | 61 | ![](https://labuladong.online/algo/images/cryptography/2.jpg) 62 | 63 | 现在 Alice 将自己心里的这个数字 `A` 和 `G` 通过某些运算得出一个数 `AG`,然后发给 Bob;Bob 将自己心里的数 `B` 和 `G` 通过相同的运算得出一个数 `BG`,然后发给 Alice: 64 | 65 | ![](https://labuladong.online/algo/images/cryptography/3.jpg) 66 | 67 | 现在的情况变成这样了: 68 | 69 | ![](https://labuladong.online/algo/images/cryptography/4.jpg) 70 | 71 | 注意,类似刚才举的散列函数的例子,知道 `AG` 和 `G`,并不能反推出 `A` 是多少,`BG` 同理。 72 | 73 | 那么,Alice 可以通过 `BG` 和自己的 `A` 通过某些运算得到一个数 `ABG`,Bob 也可以通过 `AG` 和自己的 `B` 通过某些运算得到 `ABG`,这个数就是 Alice 和 Bob 共有的秘密。 74 | 75 | 而对于 Hack,可以窃取传输过程中的 `G`,`AG`,`BG`,但是由于计算不可逆,怎么都无法结合出 `ABG` 这个数字。 76 | 77 | ![](https://labuladong.online/algo/images/cryptography/5.jpg) 78 | 79 | 以上就是基本流程,至于具体的数字取值是有讲究的,运算方法在百度上很容易找到,限于篇幅我就不具体写了。 80 | 81 | 该算法可以在第三者窃听的前提下,算出一个别人无法算出的秘密作为对称性加密算法的密钥,开始对称加密的通信。 82 | 83 | 对于该算法,Hack 又想到一种破解方法,不是窃听 Alice 和 Bob 的通信数据,而是直接同时冒充 Alice 和 Bob 的身份,也就是我们说的「**中间人攻击**」: 84 | 85 | ![](https://labuladong.online/algo/images/cryptography/6.jpg) 86 | 87 | 这样,双方根本无法察觉在和 Hack 共享秘密,后果就是 Hack 可以解密甚至修改数据。 88 | 89 | **可见,密钥交换算法也不算完全解决了密钥配送问题,缺陷在于无法核实对方身份**。所以密钥交换算法之前一般要核实对方身份,比如使用数字签名。 90 | 91 | ### 三、非对称加密 92 | 93 | 非对称加密的思路就是,干脆别偷偷摸摸传输密钥了,我把加密密钥和解密密钥分开,公钥用于加密,私钥用于解密。只把公钥传送给对方,然后对方开始给我发送加密的数据,我用私钥就可以解密。至于窃听者,拿到公钥和加密数据也没用,因为只有我手上的私钥才能解密。 94 | 95 | 可以这样想,**私钥是钥匙,而公钥是锁,可以把锁公开出去,让别人把数据锁起来发给我;而钥匙一定要留在自己手里,用于解锁**。我们常见的 RSA 算法就是典型的非对称加密算法,具体实现比较复杂,我就不写了,网上很多资料。 96 | 97 | 在实际应用中,非对称性加密的运算速度要比对称性加密慢很多的,所以传输大量数据时,一般不会用公钥直接加密数据,而是加密对称性加密的密钥,传输给对方,然后双方使用对称性加密算法传输数据。 98 | 99 | 需要注意的是,类似 Diffie-Hellman 算法,**非对称加密算法也无法确定通信双方的身份,依然会遭到中间人攻击**。比如 Hack 拦截 Bob 发出的公钥,然后冒充 Bob 的身份给 Alice 发送自己的公钥,那么不知情的 Alice 就会把私密数据用 Hack 的公钥加密,Hack 可以通过私钥解密窃取。 100 | 101 | 那么,Diffie-Hellman 算法和 RSA 非对称加密算法都可以一定程度上解决密钥配送的问题,也具有相同的缺陷,二者的应用场景有什么区别呢? 102 | 103 | 简单来说,根据两种算法的基本原理就可以看出来: 104 | 105 | 如果双方有一个对称加密方案,希望加密通信,而且不能让别人得到钥匙,那么可以使用 Diffie-Hellman 算法交换密钥。 106 | 107 | 如果你希望任何人都可以对信息加密,而只有你能够解密,那么就使用 RSA 非对称加密算法,公布公钥。 108 | 109 | 下面,我们尝试着解决认证发送方身份的问题。 110 | 111 | ### 四、数字签名 112 | 113 | 刚才说非对称加密,把公钥公开用于他人对数据加密然后发给你,只有用你手上对应的私钥才能将密文解密。其实,**私钥也可用用来加密数据的,对于 RSA 算法,私钥加密的数据只有公钥才能解开**。 114 | 115 | 数字签名也是利用了非对称性密钥的特性,但是和公钥加密完全颠倒过来:**仍然公布公钥,但是用你的私钥加密数据,然后把加密的数据公布出去,这就是数字签名**。 116 | 117 | 你可能问,这有什么用,公钥可以解开私钥加密,我还加密发出去,不是多此一举吗? 118 | 119 | 是的,但是**数字签名的作用本来就不是保证数据的机密性,而是证明你的身份**,证明这些数据确实是由你本人发出的。 120 | 121 | 你想想,你的私钥加密的数据,只有你的公钥才能解开,那么如果一份加密数据能够被你的公钥解开,不就说明这份数据是你(私钥持有者)本人发布的吗? 122 | 123 | 当然,加密数据仅仅是一个签名,签名应该和数据一同发出,具体流程应该是: 124 | 125 | 1、Bob 生成公钥和私钥,然后把公钥公布出去,私钥自己保留。 126 | 127 | 2、**用私钥加密数据作为签名,然后将数据附带着签名一同发布出去**。 128 | 129 | 3、Alice 收到数据和签名,需要检查此份数据是否是 Bob 所发出,于是用 Bob 之前发出的公钥尝试解密签名,将收到的数据和签名解密后的结果作对比,如果完全相同,说明数据没被篡改,且确实由 Bob 发出。 130 | 131 | 为什么 Alice 这么肯定呢,毕竟数据和签名是两部分,都可以被掉包呀?原因如下: 132 | 133 | 1、如果有人修改了数据,那么 Alice 解密签名之后,对比发现二者不一致,察觉出异常。 134 | 135 | 2、如果有人替换了签名,那么 Alice 用 Bob 的公钥只能解出一串乱码,显然和数据不一致。 136 | 137 | 3、也许有人企图修改数据,然后将修改之后的数据制成签名,使得 Alice 的对比无法发现不一致;但是一旦解开签名,就不可能再重新生成 Bob 的签名了,因为没有 Bob 的私钥。 138 | 139 | 综上,**数字签名可以一定程度上认证数据的来源**。之所以说是一定程度上,是因为这种方式依然可能受到中间人攻击。一旦涉及公钥的发布,接收方就可能收到中间人的假公钥,进行错误的认证,这个问题始终避免不了。 140 | 141 | 说来可笑,数字签名就是验证对方身份的一种方式,但是前提是对方的身份必须是真的... 这似乎陷入一个先有鸡还是先有蛋的死循环,**要想确定对方的身份,必须有一个信任的源头,否则的话,再多的流程也只是在转移问题,而不是真正解决问题**。 142 | 143 | ### 五、公钥证书 144 | 145 | **证书其实就是公钥 + 签名,由第三方认证机构颁发**。引入可信任的第三方,是终结信任循环的一种可行方案。 146 | 147 | 证书认证的流程大致如下: 148 | 149 | 1、Bob 去可信任的认证机构证实本人真实身份,并提供自己的公钥。 150 | 151 | 2、Alice 想跟 Bob 通信,首先向认证机构请求 Bob 的公钥,认证机构会把一张证书(Bob 的公钥以及自己对其公钥的签名)发送给 Alice。 152 | 153 | 3、Alice 检查签名,确定该公钥确实由这家认证机构发送,中途未被篡改。 154 | 155 | 4、Alice 通过这个公钥加密数据,开始和 Bob 通信。 156 | 157 | ![](https://labuladong.online/algo/images/cryptography/7.jpg) 158 | 159 | > [!NOTE] 160 | > 以上只是为了说明,证书只需要安装一次,并不需要每次都向认证机构请求;一般是服务器直接给客户端发送证书,而不是认证机构。 161 | 162 | 也许有人问,Alice 要想通过数字签名确定证书的有效性,前提是要有该机构的(认证)公钥,这不是又回到刚才的死循环了吗? 163 | 164 | 我们安装的正规浏览器中都预存了正规认证机构的证书(包含其公钥),用于确认机构身份,所以说证书的认证是可信的。 165 | 166 | Bob 向机构提供公钥的过程中,需要提供很多个人信息进行身份验证,比较严格,所以说也算是可靠的。 167 | 168 | 获得了 Bob 的可信公钥,Alice 和 Bob 之间的通信基于加密算法的保护,是完全无懈可击的。 169 | 170 | 现在的正规网站,大都使用 HTTPS 协议,就是在 HTTP 协议和 TCP 协议之间加了一个 SSL/TLS 安全层。在你的浏览器和网站服务器完成 TCP 握手后,SSL 协议层也会进行 SSL 握手交换安全参数,其中就包含该网站的证书,以便浏览器验证站点身份。SSL 安全层验证完成之后,上层的 HTTP 协议内容都会被加密,保证数据的安全传输。 171 | 172 | 这样一来,传统的中间人攻击就几乎没有了生存空间,攻击手段只能由技术缺陷转变为坑蒙拐骗。事实上,这种手段的效果反而更高效,比如我就发现**网上不少下载网站发布的浏览器,不仅包含乱七八糟的导航和收藏网址,还包含一些不正规的认证机构证书。任何人都可以申请证书,这些不正规证书很可能造成安全隐患**。 173 | 174 | ### 六、最后总结 175 | 176 | 对称性加密算法使用同一个密钥加密和解密,难以破解,加密速度较快,但是存在密钥配送问题。 177 | 178 | Diffie-Hellman 密钥交换算法可以让双方「心有灵犀一点通」,一定程度解决密钥配送问题,但是无法验证通信方的身份,所以可能受到中间人攻击。 179 | 180 | 非对称性加密算法生成一对儿密钥,把加密和解密的工作分开了。 181 | 182 | RSA 算法作为经典的非对称加密算法,有两种用途:如果用于加密,可以把公钥发布出去用于加密,只有自己的私钥可以解密,保证了数据的机密性;如果用于数字签名,把公钥发布出去后,用私钥加密数据作为签名,以证明该数据由私钥持有者所发送。但是无论那种用法,涉及公钥的发布,都无法避免中间人攻击。 183 | 184 | 公钥证书就是公钥 + 签名,由可信任的第三方认证机构颁发。由于正规浏览器都预装了可信的认证机构的公钥,所以可以有效防止中间人攻击。 185 | 186 | HTTPS 协议中的 SSL/TLS 安全层会组合使用以上几种加密方式,**所以说不要安装非正规的浏览器,不要乱安装未知来源的证书**。 187 | 188 | 密码技术只是安全的一小部分,即便是通过正规机构认证的 HTTPS 站点,也不意味着可信任,只能说明其数据传输是安全的。技术永远不可能真正保护你,最重要的还是得提高个人的安全防范意识,多留心眼儿,谨慎处理敏感数据。 189 | 190 | 191 | 192 | 193 | 194 | **_____________** 195 | 196 | 197 | 198 | ![](https://labuladong.online/algo/images/souyisou2.png) -------------------------------------------------------------------------------- /数据结构系列/README.md: -------------------------------------------------------------------------------- 1 | # 数据结构系列 2 | 3 | 这一章主要是一些特殊的数据结构设计,比如单调栈解决 Next Greater Number,单调队列解决滑动窗口问题;还有常用数据结构的操作,比如链表、树、二叉堆。 4 | 5 | 欢迎关注我的公众号 labuladong,查看全部文章: 6 | 7 | ![labuladong二维码](../pictures/qrcode.jpg) -------------------------------------------------------------------------------- /数据结构系列/二叉堆详解实现优先级队列.md: -------------------------------------------------------------------------------- 1 | # 二叉堆详解实现优先级队列 2 | 3 | 本文已重写,请阅读 [二叉堆基础原理](https://labuladong.online/algo/data-structure-basic/binary-heap-basic/) 和 [二叉堆实现优先级队列](https://labuladong.online/algo/data-structure-basic/binary-heap-implement/)。 4 | 5 | 6 | 7 | 8 | 9 | **_____________** 10 | 11 | **《labuladong 的算法笔记》已经出版,关注公众号查看详情;后台回复「**全家桶**」可下载配套 PDF 和刷题全家桶**: 12 | 13 | ![](https://labuladong.online/algo/images/souyisou2.png) 14 | 15 | ======其他语言代码====== 16 | 17 | ### javascript 18 | 19 | ```js 20 | /** 21 | * 最大堆 22 | */ 23 | function left(i) { 24 | return i * 2 + 1; 25 | } 26 | 27 | function right(i) { 28 | return i * 2 + 2; 29 | } 30 | 31 | function swap(A, i, j) { 32 | const t = A[i]; 33 | A[i] = A[j]; 34 | A[j] = t; 35 | } 36 | 37 | class Heap { 38 | constructor(arr) { 39 | this.data = [...arr]; 40 | this.size = this.data.length; 41 | } 42 | 43 | /** 44 | * 重构堆 45 | */ 46 | rebuildHeap() { 47 | const L = Math.floor(this.size / 2); 48 | for (let i = L - 1; i >= 0; i--) { 49 | this.maxHeapify(i); 50 | } 51 | } 52 | 53 | isHeap() { 54 | const L = Math.floor(this.size / 2); 55 | for (let i = L - 1; i >= 0; i++) { 56 | const l = this.data[left(i)] || Number.MIN_SAFE_INTEGER; 57 | const r = this.data[right(i)] || Number.MIN_SAFE_INTEGER; 58 | 59 | const max = Math.max(this.data[i], l, r); 60 | 61 | if (max !== this.data[i]) { 62 | return false; 63 | } 64 | return true; 65 | } 66 | } 67 | 68 | sort() { 69 | for (let i = this.size - 1; i > 0; i--) { 70 | swap(this.data, 0, i); 71 | this.size--; 72 | this.maxHeapify(0); 73 | } 74 | } 75 | 76 | insert(key) { 77 | this.data[this.size++] = key; 78 | if (this.isHeap()) { 79 | return; 80 | } 81 | this.rebuildHeap(); 82 | } 83 | 84 | delete(index) { 85 | if (index >= this.size) { 86 | return; 87 | } 88 | this.data.splice(index, 1); 89 | this.size--; 90 | if (this.isHeap()) { 91 | return; 92 | } 93 | this.rebuildHeap(); 94 | } 95 | 96 | /** 97 | * 堆的其他地方都满足性质 98 | * 唯独跟节点,重构堆性质 99 | * @param {*} i 100 | */ 101 | maxHeapify(i) { 102 | let max = i; 103 | 104 | if (i >= this.size) { 105 | return; 106 | } 107 | 108 | // 求左右节点中较大的序号 109 | const l = left(i); 110 | const r = right(i); 111 | if (l < this.size && this.data[l] > this.data[max]) { 112 | max = l; 113 | } 114 | 115 | if (r < this.size && this.data[r] > this.data[max]) { 116 | max = r; 117 | } 118 | 119 | // 如果当前节点最大,已经是最大堆 120 | if (max === i) { 121 | return; 122 | } 123 | 124 | swap(this.data, i, max); 125 | 126 | // 递归向下继续执行 127 | return this.maxHeapify(max); 128 | } 129 | } 130 | 131 | module.exports = Heap; 132 | ``` 133 | 134 | -------------------------------------------------------------------------------- /算法思维系列/README.md: -------------------------------------------------------------------------------- 1 | # 算法思维系列 2 | 3 | 本章包含一些常用的算法技巧,比如前缀和、回溯思想、位操作、双指针、如何正确书写二分查找等等。 4 | 5 | 欢迎关注我的公众号 labuladong,查看全部文章: 6 | 7 | ![labuladong二维码](../pictures/table_qr2.jpg) 8 | ![labuladong二维码](../pictures/qrcode.jpg) -------------------------------------------------------------------------------- /算法思维系列/几个反直觉的概率问题.md: -------------------------------------------------------------------------------- 1 | # 几个反直觉的概率问题 2 | 3 | 4 | 5 | ![](https://labuladong.online/algo/images/souyisou1.png) 6 | 7 | **通知:为满足广大读者的需求,网站上架 [速成目录](https://labuladong.online/algo/intro/quick-learning-plan/),如有需要可以看下,谢谢大家的支持~另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。** 8 | 9 | 10 | 11 | **-----------** 12 | 13 | 14 | 15 | 上篇文章 [谈谈游戏中的随机算法](https://labuladong.online/algo/frequency-interview/random-algorithm/) 讲到了验证概率算法的蒙特卡罗方法,今天聊点轻松的内容:几个和概率相关的有趣问题。 16 | 17 | 计算概率有下面两个最简单的原则: 18 | 19 | 原则一、计算概率一定要有一个参照系,称作「样本空间」,即随机事件可能出现的所有结果。事件 A 发生的概率 = A 包含的样本点 / 样本空间的样本总数。 20 | 21 | 原则二、计算概率一定要明白,概率是一个连续的整体,不可以把连续的概率分割开,也就是所谓的条件概率。 22 | 23 | 上述两个原则高中就学过,但是我们还是很容易犯错,而且犯错的流程也有异曲同工之妙: 24 | 25 | 先是忽略了原则二,错误地计算了样本空间,然后通过原则一算出了错误的答案。 26 | 27 | 下面介绍几个简单却具有迷惑性的问题,分别是男孩女孩问题、生日悖论、三门问题。当然,三门问题可能是大家最耳熟的,所以就多说一些有趣的思考。 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ### 一、男孩女孩问题 36 | 37 | 假设有一个家庭,有两个孩子,现在告诉你其中有一个男孩,请问另一个也是男孩的概率是多少? 38 | 39 | 很多人,包括我在内,不假思索地回答:1/2 啊,因为另一个孩子要么是男孩,要么是女孩,而且概率相等呀。但是实际上,答案是 1/3。 40 | 41 | 上述思想为什么错误呢?因为没有正确计算样本空间,导致原则一计算错误。有两个孩子,那么样本空间为 4,即哥哥妹妹,哥哥弟弟,姐姐妹妹,姐姐弟弟这四种情况。已知有一个男孩,那么排除姐姐妹妹这种情况,所以样本空间变成 3。另一个孩子也是男孩只有哥哥弟弟这 1 种情况,所以概率为 1/3。 42 | 43 | 为什么计算样本空间会出错呢?因为我们忽略了条件概率,即混淆了下面两个问题: 44 | 45 | 这个家庭只有一个孩子,这个孩子是男孩的概率是多少? 46 | 47 | 这个家庭有两个孩子,其中一个是男孩,另一个孩子是男孩的概率是多少? 48 | 49 | 根据原则二,概率问题是连续的,不可以把上述两个问题混淆。第二个问题需要用条件概率,即求一个孩子是男孩的条件下,另一个也是男孩的概率。运用条件概率的公式也很好算,就不多说了。 50 | 51 | 通过这个问题,读者应该理解两个概率计算原则的关系了,最具有迷惑性的就是条件概率的忽视。为了不要被迷惑,最简单的办法就是把所有可能结果穷举出来。 52 | 53 | 最后,对于此问题我见过一个很奇葩的质疑:如果这两个孩子是双胞胎,不存在年龄上的差异怎么办? 54 | 55 | 我竟然觉得有那么一丝道理!但其实,我们只是通过年龄差异来表示两个孩子的独立性,也就是说即便两个孩子同性,也有两种可能。所以不要用双胞胎抬杠了。 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | ### 二、生日悖论 64 | 65 | 生日悖论是由这样一个问题引出的:一个屋子里需要有多少人,才能使得存在至少两个人生日是同一天的概率达到 50%? 66 | 67 | 答案是 23 个人,也就是说房子里如果有 23 个人,那么就有 50% 的概率会存在两个人生日相同。这个结论看起来不可思议,所以被称为悖论。按照直觉,要得到 50% 的概率,起码得有 183 个人吧,因为一年有 365 天呀?其实不是的,觉得这个结论不可思议主要有两个思维误区: 68 | 69 | **第一个误区是误解「存在」这个词的含义**。 70 | 71 | 读者可能认为,如果 23 个人中出现相同生日的概率就能达到 50%,是不是意味着: 72 | 73 | 假设现在屋子里坐着 22 个人,然后我走进去,那么有 50% 的概率我可以找到一个人和我生日相同。但这怎么可能呢? 74 | 75 | 并不是的,你这种想法是以自我为中心,而题目的概率是在描述整体。也就是说「存在」的含义是指 23 人中的任意两个人,涉及排列组合,大概率和你没啥关系。 76 | 77 | 如果你非要计算存在和自己生日相同的人的概率是多少,可以这样计算: 78 | 79 | 1 - P(22 个人都和我的生日不同) = 1 -(364/365)^22 = 0.06 80 | 81 | 这样计算得到的结果是不是看起来合理多了?生日悖论计算对象的不是某一个人,而是一个整体,其中包含了所有人的排列组合,它们的概率之和当然会大得多。 82 | 83 | **第二个误区是认为概率是线性变化的**。 84 | 85 | 读者可能认为,如果 23 个人中出现相同生日的概率就能达到 50%,是不是意味着 46 个人的概率就能达到 100%? 86 | 87 | 不是的,就像中奖率 50% 的游戏,你玩两次的中奖率就是 100% 吗?显然不是,你玩两次的中奖率是 75%: 88 | 89 | `P(两次能中奖) = P(第一次就中了) + P(第一次没中但第二次中了) = 1/2 + 1/2*1/2 = 75%` 90 | 91 | 那么换到生日悖论也是一个道理,概率不是简单叠加,而要考虑一个连续的过程,所以这个结论并没有什么不合常理之处。 92 | 93 | 那为什么只要 23 个人出现相同生日的概率就能大于 50% 了呢?我们先计算 23 个人生日都唯一(不重复)的概率。只有 1 个人的时候,生日唯一的概率是 `365/365`,2 个人时,生日唯一的概率是 `365/365 × 364/365`,以此类推可知 23 人的生日都唯一的概率: 94 | 95 | ![](https://labuladong.online/algo/images/probability/p.png) 96 | 97 | 算出来大约是 0.493,所以存在相同生日的概率就是 0.507,差不多就是 50% 了。实际上,按照这个算法,当人数达到 70 时,存在两个人生日相同的概率就上升到了 99.9%,基本可以认为是 100% 了。所以从概率上说,一个几十人的小团体中存在生日相同的人真没啥稀奇的。 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | ### 三、三门问题 106 | 107 | 这个游戏很经典了:游戏参与者面对三扇门,其中两扇门后面是山羊,一扇门后面是跑车。参与者只要随便选一扇门,门后面的东西就归他(跑车的价值当然更大)。但是主持人决定帮一下参与者:在他选择之后,先不急着打开这扇门,而是由主持人打开剩下两扇门中的一扇,展示其中的山羊(主持人知道每扇门后面是什么),然后给参与者一次换门的机会,此时参与者应该换门还是不换门呢? 108 | 109 | 为了防止第一次看到这个问题的读者迷惑,再具体描述一下这个问题: 110 | 111 | 你是游戏参与者,现在有门 1,2,3,假设你随机选择了门 1,然后主持人打开了门 3 告诉你那后面是山羊。现在,你是坚持你最初的选择门 1,还是选择换成门 2 呢? 112 | 113 | ![](https://labuladong.online/algo/images/probability/sanmen.png) 114 | 115 | 答案是应该换门,换门之后抽到跑车的概率是 2/3,不换的话是 1/3。又一次反直觉,感觉换不换的中奖概率应该都一样啊,因为最后肯定就剩两个门,一个是羊,一个是跑车,这是事实,所以不管选哪个的概率不都是 1/2 吗? 116 | 117 | 类似前面说的男孩女孩问题,最简单稳妥的方法就是把所有可能结果穷举出来: 118 | 119 | ![](https://labuladong.online/algo/images/probability/tree.png) 120 | 121 | 很容易看到选择换门中奖的概率是 2/3,不换的话是 1/3。 122 | 123 | 关于这个问题还有更简单的方法:主持人开门实际上在「浓缩」概率。一开始你选择到跑车的概率当然是 1/3,剩下两个门中包含跑车的概率当然是 2/3,这没啥可说的。但是主持人帮你排除了一个含有山羊的门,相当于把那 2/3 的概率浓缩到了剩下的这一扇门上。那么,你说你是抱着原来那扇 1/3 的门,还是换成那扇经过「浓缩」的 2/3 概率的门呢? 124 | 125 | 再直观一点,假设你三选一,剩下 2 扇门,再给你加入 98 扇装山羊的门,把这 100 扇门随机打乱,问你换不换?肯定不换对吧,这明摆着把概率稀释了,肯定抱着原来的那扇门是最可能中跑车的。再假设,初始有 100 扇门,你选了一扇,然后主持人在剩下 99 扇门中帮你排除 98 个山羊,问你换不换一扇门?肯定换对吧,你手上那扇门是 1%,另一扇门是 99%,或者也可以这样理解,不换只是选择了 1 扇门,换门相当于选择了 99 扇门,这样结果很明显了吧? 126 | 127 | 以上思想,也许有的读者都思考过,下面我们思考这样一个问题:假设你在决定是否换门的时候,小明破门而入,要求帮你做出选择。他完全不知道之前发生的事,他只知道面前有两扇门,一扇是跑车一扇是山羊,那么他抽中跑车的概率是多大? 128 | 129 | 当然是 1/2,这也是很多人做错三门问题的根本原因。类似生日悖论,人们总是容易以自我为中心,通过这个小明的视角来计算是否换门,这显然会进入误区。 130 | 131 | 就好比有两个箱子,一号箱子有 4 个黑球 2 个红球,二号箱子有 2 个黑球 4 个红球,随便选一个箱子,随便摸一个球,问你摸出红球的概率。 132 | 133 | 对于不知情的小明,他会随机选择一个箱子,随机摸球,摸到红球的概率是:1/2 × 2/6 + 1/2 × 4/6 = 1/2 134 | 135 | 对于知情的你,你知道在二号箱子摸球概率大,所以只在二号箱摸,摸到红球的概率是:0 × 2/6 + 1 × 4/6 = 2/3 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | **_____________** 146 | 147 | 148 | 149 | ![](https://labuladong.online/algo/images/souyisou2.png) -------------------------------------------------------------------------------- /算法思维系列/字符串乘法.md: -------------------------------------------------------------------------------- 1 | # 字符串乘法计算 2 | 3 | 4 | 5 | ![](https://labuladong.online/algo/images/souyisou1.png) 6 | 7 | **通知:为满足广大读者的需求,网站上架 [速成目录](https://labuladong.online/algo/intro/quick-learning-plan/),如有需要可以看下,谢谢大家的支持~另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。** 8 | 9 | 10 | 11 | 读完本文,你不仅学会了算法套路,还可以顺便解决如下题目: 12 | 13 | | LeetCode | 力扣 | 难度 | 14 | | :----: | :----: | :----: | 15 | | [43. Multiply Strings](https://leetcode.com/problems/multiply-strings/) | [43. 字符串相乘](https://leetcode.cn/problems/multiply-strings/) | 🟠 | 16 | 17 | **-----------** 18 | 19 | 20 | 21 | 对于比较小的数字,做运算可以直接使用编程语言提供的运算符,但是如果相乘的两个因数非常大,语言提供的数据类型可能就会溢出。一种替代方案就是,运算数以字符串的形式输入,然后模仿我们小学学习的乘法算术过程计算出结果,并且也用字符串表示。 22 | 23 | 看下力扣第 43 题「字符串相乘」: 24 | 25 | 26 | 27 | 需要注意的是,`num1` 和 `num2` 可以非常长,所以不可以把他们直接转成整型然后运算,唯一的思路就是模仿我们手算乘法。 28 | 29 | 比如说我们手算 `123 × 45`,应该会这样计算: 30 | 31 | ![](https://labuladong.online/algo/images/string-multiply/1.jpg) 32 | 33 | 计算 `123 × 5`,再计算 `123 × 4`,最后错一位相加。这个流程恐怕小学生都可以熟练完成,但是你是否能**把这个运算过程进一步机械化**,写成一套算法指令让没有任何智商的计算机来执行呢? 34 | 35 | 你看这个简单过程,其中涉及乘法进位,涉及错位相加,还涉及加法进位;而且还有一些不易察觉的问题,比如说两位数乘以两位数,结果可能是四位数,也可能是三位数,你怎么想出一个标准化的处理方式?这就是算法的魅力,如果没有计算机思维,简单的问题可能都没办法自动化处理。 36 | 37 | 首先,我们这种手算方式还是太「高级」了,我们要再「低级」一点,`123 × 5` 和 `123 × 4` 的过程还可以进一步分解,最后再相加: 38 | 39 | ![](https://labuladong.online/algo/images/string-multiply/2.jpg) 40 | 41 | 现在 `123` 并不大,如果是个很大的数字的话,是无法直接计算乘积的。我们可以用一个数组在底下接收相加结果: 42 | 43 | ![](https://labuladong.online/algo/images/string-multiply/3.jpg) 44 | 45 | 整个计算过程大概是这样,**有两个指针 `i,j` 在 `num1` 和 `num2` 上游走,计算乘积,同时将乘积叠加到 `res` 的正确位置**,如下 GIF 图所示: 46 | 47 | ![](https://labuladong.online/algo/images/string-multiply/4.gif) 48 | 49 | 现在还有一个关键问题,如何将乘积叠加到 `res` 的正确位置,或者说,如何通过 `i,j` 计算 `res` 的对应索引呢? 50 | 51 | 其实,细心观察之后就发现,**`num1[i]` 和 `num2[j]` 的乘积对应的就是 `res[i+j]` 和 `res[i+j+1]` 这两个位置**。 52 | 53 | ![](https://labuladong.online/algo/images/string-multiply/6.jpg) 54 | 55 | 明白了这一点,就可以用代码模仿出这个计算过程了: 56 | 57 | ```java 58 | class Solution { 59 | public String multiply(String num1, String num2) { 60 | int m = num1.length(), n = num2.length(); 61 | // 结果最多为 m + n 位数 62 | int[] res = new int[m + n]; 63 | // 从个位数开始逐位相乘 64 | for (int i = m - 1; i >= 0; i--) { 65 | for (int j = n - 1; j >= 0; j--) { 66 | int mul = (num1.charAt(i) - '0') * (num2.charAt(j) - '0'); 67 | // 乘积在 res 对应的索引位置 68 | int p1 = i + j, p2 = i + j + 1; 69 | // 叠加到 res 上 70 | int sum = mul + res[p2]; 71 | res[p2] = sum % 10; 72 | res[p1] += sum / 10; 73 | } 74 | } 75 | // 结果前缀可能存的 0(未使用的位) 76 | int i = 0; 77 | while (i < res.length && res[i] == 0) 78 | i++; 79 | // 将计算结果转化成字符串 80 | StringBuilder str = new StringBuilder(); 81 | for (; i < res.length; i++) 82 | str.append(res[i]); 83 | 84 | return str.length() == 0 ? "0" : str.toString(); 85 | } 86 | } 87 | ``` 88 | 89 | 至此,字符串乘法算法就完成了。 90 | 91 | **总结一下**,我们习以为常的一些思维方式,在计算机看来是非常难以做到的。比如说我们习惯的算术流程并不复杂,但是如果让你再进一步,翻译成代码逻辑,并不简单。算法需要将计算流程再简化,通过边算边叠加的方式来得到结果。 92 | 93 | 俗话教育我们,不要陷入思维定式,不要程序化,要发散思维,要创新。但我觉得程序化并不是坏事,可以大幅提高效率,减小失误率。算法不就是一套程序化的思维吗,只有程序化才能让计算机帮助我们解决复杂问题呀! 94 | 95 | 也许算法就是一种**寻找思维定式的思维**吧,希望本文对你有帮助。 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | **_____________** 106 | 107 | 108 | 109 | ![](https://labuladong.online/algo/images/souyisou2.png) -------------------------------------------------------------------------------- /算法思维系列/烧饼排序.md: -------------------------------------------------------------------------------- 1 | # 烧饼排序算法 2 | 3 | 4 | 5 | ![](https://labuladong.online/algo/images/souyisou1.png) 6 | 7 | **通知:为满足广大读者的需求,网站上架 [速成目录](https://labuladong.online/algo/intro/quick-learning-plan/),如有需要可以看下,谢谢大家的支持~另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。** 8 | 9 | 10 | 11 | 读完本文,你不仅学会了算法套路,还可以顺便解决如下题目: 12 | 13 | | LeetCode | 力扣 | 难度 | 14 | | :----: | :----: | :----: | 15 | | [969. Pancake Sorting](https://leetcode.com/problems/pancake-sorting/) | [969. 煎饼排序](https://leetcode.cn/problems/pancake-sorting/) | 🟠 | 16 | 17 | **-----------** 18 | 19 | 20 | 21 | 力扣第 969 题「煎饼排序」是个很有意思的实际问题:假设盘子上有 `n` 块**面积大小不一**的烧饼,你如何用一把锅铲进行若干次翻转,让这些烧饼的大小有序(小的在上,大的在下)? 22 | 23 | ![](https://labuladong.online/algo/images/pancakeSort/1.jpg) 24 | 25 | 设想一下用锅铲翻转一堆烧饼的情景,其实是有一点限制的,我们每次只能将最上面的若干块饼子翻转: 26 | 27 | ![](https://labuladong.online/algo/images/pancakeSort/2.png) 28 | 29 | 我们的问题是,**如何使用算法得到一个翻转序列,使得烧饼堆变得有序**? 30 | 31 | 首先,需要把这个问题抽象,用数组来表示烧饼堆: 32 | 33 | 34 | 35 | 如何解决这个问题呢?其实类似上篇文章 [递归反转链表的一部分](https://labuladong.online/algo/data-structure/reverse-linked-list-recursion/),这也是需要**递归思想**的。 36 | 37 | ### 一、思路分析 38 | 39 | 为什么说这个问题有递归性质呢?比如说我们需要实现这样一个函数: 40 | 41 | ```java 42 | // cakes 是一堆烧饼,函数会将前 n 个烧饼排序 43 | void sort(int[] cakes, int n); 44 | ``` 45 | 46 | 如果我们找到了前 `n` 个烧饼中最大的那个,然后设法将这个饼子翻转到最底下: 47 | 48 | ![](https://labuladong.online/algo/images/pancakeSort/3.jpg) 49 | 50 | 那么,原问题的规模就可以减小,递归调用 `pancakeSort(A, n-1)` 即可: 51 | 52 | ![](https://labuladong.online/algo/images/pancakeSort/4.jpg) 53 | 54 | 接下来,对于上面的这 `n - 1` 块饼,如何排序呢?还是先从中找到最大的一块饼,然后把这块饼放到底下,再递归调用 `pancakeSort(A, n-1-1)`…… 55 | 56 | 你看,这就是递归性质,总结一下思路就是: 57 | 58 | 1、找到 `n` 个饼中最大的那个。 59 | 60 | 2、把这个最大的饼移到最底下。 61 | 62 | 3、递归调用 `pancakeSort(A, n - 1)`。 63 | 64 | base case:`n == 1` 时,排序 1 个饼时不需要翻转。 65 | 66 | 那么,最后剩下个问题,**如何设法将某块烧饼翻到最后呢**? 67 | 68 | 其实很简单,比如第 3 块饼是最大的,我们想把它换到最后,也就是换到第 `n` 块。可以这样操作: 69 | 70 | 1、用锅铲将前 3 块饼翻转一下,这样最大的饼就翻到了最上面。 71 | 72 | 2、用锅铲将前 `n` 块饼全部翻转,这样最大的饼就翻到了第 `n` 块,也就是最后一块。 73 | 74 | 以上两个流程理解之后,基本就可以写出解法了,不过题目要求我们写出具体的反转操作序列,这也很简单,只要在每次翻转烧饼时记录下来就行了。 75 | 76 | ### 二、代码实现 77 | 78 | 只要把上述的思路用代码实现即可,唯一需要注意的是,数组索引从 0 开始,而我们要返回的结果是从 1 开始算的。 79 | 80 | ```java 81 | class Solution { 82 | // 记录反转操作序列 83 | LinkedList res = new LinkedList<>(); 84 | 85 | public List pancakeSort(int[] cakes) { 86 | sort(cakes, cakes.length); 87 | return res; 88 | } 89 | 90 | void sort(int[] cakes, int n) { 91 | // base case 92 | if (n == 1) return; 93 | 94 | // 寻找最大饼的索引 95 | int maxCake = 0; 96 | int maxCakeIndex = 0; 97 | for (int i = 0; i < n; i++) 98 | if (cakes[i] > maxCake) { 99 | maxCakeIndex = i; 100 | maxCake = cakes[i]; 101 | } 102 | 103 | // 第一次翻转,将最大饼翻到最上面 104 | reverse(cakes, 0, maxCakeIndex); 105 | res.add(maxCakeIndex + 1); 106 | // 第二次翻转,将最大饼翻到最下面 107 | reverse(cakes, 0, n - 1); 108 | res.add(n); 109 | 110 | // 递归调用 111 | sort(cakes, n - 1); 112 | } 113 | 114 | void reverse(int[] arr, int i, int j) { 115 | while (i < j) { 116 | int temp = arr[i]; 117 | arr[i] = arr[j]; 118 | arr[j] = temp; 119 | i++; j--; 120 | } 121 | } 122 | } 123 | ``` 124 | 125 | 126 |
127 | 128 |
129 | 130 | 🌟 代码可视化动画🌟 131 | 132 |
133 |
134 |
135 | 136 | 137 | 138 | 通过刚才的详细解释,这段代码应该是很清晰了。 139 | 140 | 算法的时间复杂度很容易计算,因为递归调用的次数是 `n`,每次递归调用都需要一次 for 循环,时间复杂度是 O(n),所以总的复杂度是 O(n^2)。 141 | 142 | **最后,我们可以思考一个问题**:按照我们这个思路,得出的操作序列长度应该为 `2(n - 1)`,因为每次递归都要进行 2 次翻转并记录操作,总共有 `n` 层递归,但由于 base case 直接返回结果,不进行翻转,所以最终的操作序列长度应该是固定的 `2(n - 1)`。 143 | 144 | 显然,这个结果不是最优的(最短的),比如说一堆煎饼 `[3,2,4,1]`,我们的算法得到的翻转序列是 `[3,4,2,3,1,2]`,但是最快捷的翻转方法应该是 `[2,3,4]`: 145 | 146 | ``` 147 | 初始状态 :[3,2,4,1] 148 | 翻前 2 个:[2,3,4,1] 149 | 翻前 3 个:[4,3,2,1] 150 | 翻前 4 个:[1,2,3,4] 151 | ``` 152 | 153 | 如果要求你的算法计算排序烧饼的**最短**操作序列,你该如何计算呢?或者说,解决这种求最优解法的问题,核心思路什么,一定需要使用什么算法技巧呢? 154 | 155 | 不妨分享一下你的思考。 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | **_____________** 166 | 167 | 168 | 169 | ![](https://labuladong.online/algo/images/souyisou2.png) -------------------------------------------------------------------------------- /高频面试系列/README.md: -------------------------------------------------------------------------------- 1 | # 高频面试系列 2 | 3 | 8 说了,本章都是高频面试题,配合前面的动态规划系列,祝各位马到成功! 4 | 5 | 欢迎关注我的公众号 labuladong,查看全部文章: 6 | 7 | ![labuladong二维码](../pictures/qrcode.jpg) -------------------------------------------------------------------------------- /高频面试系列/名人问题.md: -------------------------------------------------------------------------------- 1 | # 众里寻他千百度:名流问题 2 | 3 | 4 | 5 | ![](https://labuladong.online/algo/images/souyisou1.png) 6 | 7 | **通知:为满足广大读者的需求,网站上架 [速成目录](https://labuladong.online/algo/intro/quick-learning-plan/),如有需要可以看下,谢谢大家的支持~另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。** 8 | 9 | 10 | 11 | 读完本文,你不仅学会了算法套路,还可以顺便解决如下题目: 12 | 13 | | LeetCode | 力扣 | 难度 | 14 | | :----: | :----: | :----: | 15 | | [277. Find the Celebrity](https://leetcode.com/problems/find-the-celebrity/)🔒 | [277. 搜寻名人](https://leetcode.cn/problems/find-the-celebrity/)🔒 | 🟠 | 16 | 17 | **-----------** 18 | 19 | 20 | 21 | > [!NOTE] 22 | > 阅读本文前,你需要先学习: 23 | > 24 | > - [图结构基础及通用实现](https://labuladong.online/algo/data-structure-basic/graph-basic/) 25 | 26 | 今天来讨论经典的「名流问题」: 27 | 28 | 给你 `n` 个人的社交关系(你知道任意两个人之间是否认识),然后请你找出这些人中的「名人」。 29 | 30 | 所谓「名人」有两个条件: 31 | 32 | 1、所有其他人都认识「名人」。 33 | 34 | 2、「名人」不认识任何其他人。 35 | 36 | 这是一个图相关的算法问题,社交关系嘛,本质上就可以抽象成一幅图。 37 | 38 | 如果把每个人看做图中的节点,「认识」这种关系看做是节点之间的有向边,那么名人就是这幅图中一个特殊的节点: 39 | 40 | ![](https://labuladong.online/algo/images/celebrity/1.jpeg) 41 | 42 | **这个节点没有一条指向其他节点的有向边;且其他所有节点都有一条指向这个节点的有向边**。 43 | 44 | 或者说的专业一点,名人节点的出度为 0,入度为 `n - 1`。 45 | 46 | 那么,这 `n` 个人的社交关系是如何表示的呢? 47 | 48 | 前文 [图论算法基础](https://labuladong.online/algo/data-structure-basic/graph-basic/) 说过,图有两种存储形式,一种是邻接表,一种是邻接矩阵,邻接表的主要优势是节约存储空间;邻接矩阵的主要优势是可以迅速判断两个节点是否相邻。 49 | 50 | 对于名人问题,显然会经常需要判断两个人之间是否认识,也就是两个节点是否相邻,所以我们可以用邻接矩阵来表示人和人之间的社交关系。 51 | 52 | 那么,把名流问题描述成算法的形式就是这样的: 53 | 54 | 给你输入一个大小为 `n x n` 的二维数组(邻接矩阵) `graph` 表示一幅有 `n` 个节点的图,每个人都是图中的一个节点,编号为 `0` 到 `n - 1`。 55 | 56 | 如果 `graph[i][j] == 1` 代表第 `i` 个人认识第 `j` 个人,如果 `graph[i][j] == 0` 代表第 `i` 个人不认识第 `j` 个人。 57 | 58 | 有了这幅图表示人与人之间的关系,请你计算,这 `n` 个人中,是否存在「名人」? 59 | 60 | 如果存在,算法返回这个名人的编号,如果不存在,算法返回 -1。 61 | 62 | 函数签名如下: 63 | 64 | ```java 65 | int findCelebrity(int[][] graph); 66 | ``` 67 | 68 | 比如输入的邻接矩阵长这样: 69 | 70 | ![](https://labuladong.online/algo/images/celebrity/2.jpeg) 71 | 72 | 那么算法应该返回 2。 73 | 74 | 力扣第 277 题「搜寻名人」就是这个经典问题,不过并不是直接把邻接矩阵传给你,而是只告诉你总人数 `n`,同时提供一个 API `knows` 来查询人和人之间的社交关系: 75 | 76 | ```java 77 | // 可以直接调用,能够返回 i 是否认识 j 78 | boolean knows(int i, int j); 79 | 80 | // 请你实现:返回「名人」的编号 81 | int findCelebrity(int n) { 82 | // todo 83 | } 84 | ``` 85 | 86 | 很明显,`knows` API 本质上还是在访问邻接矩阵。为了简单起见,我们后面就按力扣的题目形式来探讨一下这个经典问题。 87 | 88 | ## 暴力解法 89 | 90 | 我们拍拍脑袋就能写出一个简单粗暴的算法: 91 | 92 | ```java 93 | class Solution extends Relation { 94 | public int findCelebrity(int n) { 95 | for (int cand = 0; cand < n; cand++) { 96 | int other; 97 | for (other = 0; other < n; other++) { 98 | if (cand == other) continue; 99 | // 保证其他人都认识 cand,且 cand 不认识任何其他人 100 | // 否则 cand 就不可能是名人 101 | if (knows(cand, other) || !knows(other, cand)) { 102 | break; 103 | } 104 | } 105 | if (other == n) { 106 | // 找到名人 107 | return cand; 108 | } 109 | } 110 | // 没有一个人符合名人特性 111 | return -1; 112 | } 113 | } 114 | ``` 115 | 116 | `cand` 是候选人(candidate)的缩写,我们的暴力算法就是从头开始穷举,把每个人都视为候选人,判断是否符合「名人」的条件。 117 | 118 | 刚才也说了,`knows` 函数底层就是在访问一个二维的邻接矩阵,一次调用的时间复杂度是 O(1),所以这个暴力解法整体的最坏时间复杂度是 O(N^2)。 119 | 120 | 那么,是否有其他高明的办法来优化时间复杂度呢?其实是有优化空间的,你想想,我们现在最耗时的地方在哪里? 121 | 122 | 对于每一个候选人 `cand`,我们都要用一个内层 for 循环去判断这个 `cand` 到底符不符合「名人」的条件。 123 | 124 | 这个内层 for 循环看起来就蠢,虽然判断一个人「是名人」必须用一个 for 循环,但判断一个人「不是名人」就不用这么麻烦了。 125 | 126 | **因为「名人」的定义保证了「名人」的唯一性,所以我们可以利用排除法,先排除那些显然不是「名人」的人,从而避免 for 循环的嵌套,降低时间复杂度**。 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | ## 优化解法 135 | 136 | 我再重复一遍所谓「名人」的定义: 137 | 138 | 1、所有其他人都认识名人。 139 | 140 | 2、名人不认识任何其他人。 141 | 142 | 这个定义就很有意思,它保证了人群中最多有一个名人。 143 | 144 | 这很好理解,如果有两个人同时是名人,那么这两条定义就自相矛盾了。 145 | 146 | **换句话说,只要观察任意两个候选人的关系,我一定能确定其中的一个人不是名人,把他排除**。 147 | 148 | 至于另一个候选人是不是名人,只看两个人的关系肯定是不能确定的,但这不重要,重要的是排除掉一个必然不是名人的候选人,缩小了包围圈。 149 | 150 | 这是优化的核心,也是比较难理解的,所以我们先来说说为什么观察任意两个候选人的关系,就能排除掉一个。 151 | 152 | 你想想,两个人之间的关系可能是什么样的? 153 | 154 | 无非就是四种:你认识我我不认识你,我认识你你不认识我,咱俩互相认识,咱两互相不认识。 155 | 156 | 如果把人比作节点,红色的有向边表示不认识,绿色的有向边表示认识,那么两个人的关系无非是如下四种情况: 157 | 158 | ![](https://labuladong.online/algo/images/celebrity/3.jpeg) 159 | 160 | 不妨认为这两个人的编号分别是 `cand` 和 `other`,然后我们逐一分析每种情况,看看怎么排除掉一个人。 161 | 162 | 对于情况一,`cand` 认识 `other`,所以 `cand` 肯定不是名人,排除。因为名人不可能认识别人。 163 | 164 | 对于情况二,`other` 认识 `cand`,所以 `other` 肯定不是名人,排除。 165 | 166 | 对于情况三,他俩互相认识,肯定都不是名人,可以随便排除一个。 167 | 168 | 对于情况四,他俩互不认识,肯定都不是名人,可以随便排除一个。因为名人应该被所有其他人认识。 169 | 170 | 综上,只要观察任意两个之间的关系,就至少能确定一个人不是名人,上述情况判断可以用如下代码表示: 171 | 172 | ```java 173 | if (knows(cand, other) || !knows(other, cand)) { 174 | // cand 不可能是名人 175 | } else { 176 | // other 不可能是名人 177 | } 178 | ``` 179 | 180 | 如果能够理解这一个特点,那么写出优化解法就简单了。 181 | 182 | **我们可以不断从候选人中选两个出来,然后排除掉一个,直到最后只剩下一个候选人,这时候再使用一个 for 循环判断这个候选人是否是货真价实的「名人」**。 183 | 184 | 这个思路的完整代码如下: 185 | 186 | ```java 187 | class Solution extends Relation { 188 | public int findCelebrity(int n) { 189 | if (n == 1) return 0; 190 | // 将所有候选人装进队列 191 | LinkedList q = new LinkedList<>(); 192 | for (int i = 0; i < n; i++) { 193 | q.addLast(i); 194 | } 195 | // 一直排除,直到只剩下一个候选人停止循环 196 | while (q.size() >= 2) { 197 | // 每次取出两个候选人,排除一个 198 | int cand = q.removeFirst(); 199 | int other = q.removeFirst(); 200 | if (knows(cand, other) || !knows(other, cand)) { 201 | // cand 不可能是名人,排除,让 other 归队 202 | q.addFirst(other); 203 | } else { 204 | // other 不可能是名人,排除,让 cand 归队 205 | q.addFirst(cand); 206 | } 207 | } 208 | 209 | // 现在排除得只剩一个候选人,判断他是否真的是名人 210 | int cand = q.removeFirst(); 211 | for (int other = 0; other < n; other++) { 212 | if (other == cand) { 213 | continue; 214 | } 215 | // 保证其他人都认识 cand,且 cand 不认识任何其他人 216 | if (!knows(other, cand) || knows(cand, other)) { 217 | return -1; 218 | } 219 | } 220 | // cand 是名人 221 | return cand; 222 | } 223 | } 224 | ``` 225 | 226 | 这个算法避免了嵌套 for 循环,时间复杂度降为 O(N) 了,不过引入了一个队列来存储候选人集合,使用了 O(N) 的空间复杂度。 227 | 228 | > [!NOTE] 229 | > `LinkedList` 的作用只是充当一个容器把候选人装起来,每次找出两个进行比较和淘汰,但至于具体找出哪两个,都是无所谓的,也就是说候选人归队的顺序无所谓,我们用的是 `addFirst` 只是方便后续的优化,你完全可以用 `addLast`,结果都是一样的。 230 | 231 | 是否可以进一步优化,把空间复杂度也优化掉? 232 | 233 | ## 最终解法 234 | 235 | 如果你能够理解上面的优化解法,其实可以不需要额外的空间解决这个问题,代码如下: 236 | 237 | ```java 238 | class Solution extends Relation { 239 | public int findCelebrity(int n) { 240 | int cand = 0; 241 | for (int other = 1; other < n; other++) { 242 | if (!knows(other, cand) || knows(cand, other)) { 243 | // cand 不可能是名人,排除 244 | // 假设 other 是名人 245 | cand = other; 246 | } else { 247 | // other 不可能是名人,排除 248 | // 什么都不用做,继续假设 cand 是名人 249 | } 250 | } 251 | 252 | // 现在的 cand 是排除的最后结果,但不能保证一定是名人 253 | for (int other = 0; other < n; other++) { 254 | if (cand == other) continue; 255 | // 需要保证其他人都认识 cand,且 cand 不认识任何其他人 256 | if (!knows(other, cand) || knows(cand, other)) { 257 | return -1; 258 | } 259 | } 260 | 261 | return cand; 262 | } 263 | } 264 | ``` 265 | 266 | 我们之前的解法用到了 `LinkedList` 充当一个队列,用于存储候选人集合,而这个优化解法利用 `other` 和 `cand` 的交替变化,模拟了我们之前操作队列的过程,避免了使用额外的存储空间。 267 | 268 | 现在,解决名人问题的解法时间复杂度为 O(N),空间复杂度为 O(1),已经是最优解法了。 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | **_____________** 279 | 280 | 281 | 282 | ![](https://labuladong.online/algo/images/souyisou2.png) -------------------------------------------------------------------------------- /高频面试系列/安排会议室.md: -------------------------------------------------------------------------------- 1 | # 扫描线技巧:安排会议室 2 | 3 | 4 | 5 | ![](https://labuladong.online/algo/images/souyisou1.png) 6 | 7 | **通知:为满足广大读者的需求,网站上架 [速成目录](https://labuladong.online/algo/intro/quick-learning-plan/),如有需要可以看下,谢谢大家的支持~另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。** 8 | 9 | 10 | 11 | 读完本文,你不仅学会了算法套路,还可以顺便解决如下题目: 12 | 13 | | LeetCode | 力扣 | 难度 | 14 | | :----: | :----: | :----: | 15 | | [253. Meeting Rooms II](https://leetcode.com/problems/meeting-rooms-ii/)🔒 | [253. 会议室 II](https://leetcode.cn/problems/meeting-rooms-ii/)🔒 | 🟠 | 16 | 17 | **-----------** 18 | 19 | 20 | 21 | 之前面试,被问到一道非常经典且非常实用的算法题目:会议室安排问题。 22 | 23 | 力扣上类似的问题是会员题目,你可能没办法做,但对于这种经典的算法题,掌握思路还是必要的。 24 | 25 | 先说下题目,力扣第 253 题「会议室 II」: 26 | 27 | 给你输入若干形如 `[begin, end]` 的区间,代表若干会议的开始时间和结束时间,请你计算至少需要申请多少间会议室。 28 | 29 | 函数签名如下: 30 | 31 | ```java 32 | // 返回需要申请的会议室数量 33 | int minMeetingRooms(int[][] meetings); 34 | ``` 35 | 36 | 比如给你输入 `meetings = [[0,30],[5,10],[15,20]]`,算法应该返回 2,因为后两个会议和第一个会议时间是冲突的,至少申请两个会议室才能让所有会议顺利进行。 37 | 38 | 如果会议之间的时间有重叠,那就得额外申请会议室来开会,想求至少需要多少间会议室,就是让你计算同一时刻最多有多少会议在同时进行。 39 | 40 | 换句话说,**如果把每个会议的起始时间看做一个线段区间,那么题目就是让你求最多有几个重叠区间**,仅此而已。 41 | 42 | 我们之前也学习过区间相关的算法,如果你对 [差分数组技巧](https://labuladong.online/algo/data-structure/diff-array/) 有印象,应该首先能想到用那个技巧来解决这个题。 43 | 44 | 这道题相当于是说,给你一个原本全是 0 的数组,然后给你若干区间,让你对每个区间中的元素都加 1,问你最后整个数组中的最大值是多少。这就是经典的差分数组实用场景对吧,直接套用前文给的 `Difference` 类就可以解决这个问题了。 45 | 46 | 但是差分数组技巧有一个问题,就是你必须把那个全是 0 的初始数组构造出来。由于我们用数组的索引表示时间,所以这个数组的长度取决于时间区间的最大值。 47 | 48 | 比如输入 `meetings = [[0,30],[5,10],[15,20]]`,那么你得构造一个长度为 30 的数组。那如果输入 `meetings = [[0,30],[5,10],[10^8,10^9]]`,这样的话你就得构造一个长度为 10^9 的数组,这显然是有问题的。不过这道题给的数据规模是时间的取值最多为 10^6,不算是特别大,用差分数组的方法应该可以通过。 49 | 50 | 但本文再教你另外的一个处理区间的技巧,不用构造这么大的数组,也能巧妙解决这个问题。 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | ## 题目延伸 59 | 60 | 我们之前写过很多区间调度相关的文章,这里就顺便帮大家梳理一下这类问题的思路: 61 | 62 | **第一个场景**,假设现在只有一个会议室,还有若干会议,你如何将尽可能多的会议安排到这个会议室里? 63 | 64 | 这个问题需要将这些会议(区间)按结束时间(右端点)排序,然后进行处理,详见前文 [贪心算法做时间管理](https://labuladong.online/algo/frequency-interview/interval-scheduling/)。 65 | 66 | **第二个场景**,给你若干较短的视频片段,和一个较长的视频片段,请你从较短的片段中尽可能少地挑出一些片段,拼接出较长的这个片段。 67 | 68 | 这个问题需要将这些视频片段(区间)按开始时间(左端点)排序,然后进行处理,详见前文 [剪视频剪出一个贪心算法](https://labuladong.online/algo/frequency-interview/cut-video/)。 69 | 70 | **第三个场景**,给你若干区间,其中可能有些区间比较短,被其他区间完全覆盖住了,请你删除这些被覆盖的区间。 71 | 72 | 这个问题需要将这些区间按左端点排序,然后就能找到并删除那些被完全覆盖的区间了,详见前文 [删除覆盖区间](https://labuladong.online/algo/practice-in-action/interval-problem-summary/)。 73 | 74 | **第四个场景**,给你若干区间,请你将所有有重叠部分的区间进行合并。 75 | 76 | 这个问题需要将这些区间按左端点排序,方便找出存在重叠的区间,详见前文 [合并重叠区间](https://labuladong.online/algo/practice-in-action/interval-problem-summary/)。 77 | 78 | **第五个场景**,有两个部门同时预约了同一个会议室的若干时间段,请你计算会议室的冲突时段。 79 | 80 | 这个问题就是给你两组区间列表,请你找出这两组区间的交集,这需要你将这些区间按左端点排序,详见前文 [区间交集问题](https://labuladong.online/algo/practice-in-action/interval-problem-summary/)。 81 | 82 | **第六个场景**,假设现在只有一个会议室,还有若干会议,如何安排会议才能使这个会议室的闲置时间最少? 83 | 84 | 这个问题需要动动脑筋,说白了这就是个 0-1 背包问题的变形: 85 | 86 | 会议室可以看做一个背包,每个会议可以看做一个物品,物品的价值就是会议的时长,请问你如何选择物品(会议)才能最大化背包中的价值(会议室的使用时长)? 87 | 88 | 当然,这里背包的约束不是一个最大重量,而是各个物品(会议)不能互相冲突。把各个会议按照结束时间进行排序,然后参考前文 [0-1 背包问题详解](https://labuladong.online/algo/dynamic-programming/knapsack1/) 的思路和 TreeMap 即可解决。 89 | 90 | 力扣第 1235 题「规划兼职工作」就是类似的题目,我在插件思路中给出了详细的解答,你可以安装我的 [Chrome 插件](https://labuladong.online/algo/intro/chrome/) 去查看,我在这里就不花费篇幅了。 91 | 92 | **第七个场景**,就是本文想讲的场景,给你若干会议,让你最小化申请会议室的数量。 93 | 94 | 好了,举例了这么多,来看看今天的这个问题如何解决。 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | ## 题目分析 103 | 104 | 重复一下题目的本质: 105 | 106 | **给你输入若干时间区间,让你计算同一时刻「最多」有几个区间重叠**。 107 | 108 | 题目的关键点在于,给你任意一个时刻,你是否能够说出这个时刻有几个会议? 109 | 110 | 如果可以做到,那我遍历所有的时刻,找个最大值,就是需要申请的会议室数量。 111 | 112 | 有没有一种数据结构或者算法,给我输入若干区间,我能知道每个位置有多少个区间重叠? 113 | 114 | 老读者肯定可以联想到之前说过的一个算法技巧:[差分数组技巧](https://labuladong.online/algo/data-structure/diff-array/)。 115 | 116 | 把时间线想象成一个初始值为 0 的数组,每个时间区间 `[i, j]` 就相当于一个子数组,这个时间区间有一个会议,那我就把这个子数组中的元素都加一。 117 | 118 | 最后,每个时刻有几个会议我不就知道了吗?我遍历整个数组,不就知道至少需要几间会议室了吗? 119 | 120 | 举例来说,如果输入 `meetings = [[0,30],[5,10],[15,20]]`,那么我们就给数组中 `[0,30],[5,10],[15,20]` 这几个索引区间分别加一,最后遍历数组,求个最大值就行了。 121 | 122 | 还记得吗,差分数组技巧可以在 O(1) 时间对整个区间的元素进行加减,所以可以拿来解决这道题。 123 | 124 | 不过,这个解法的效率不算高,所以我这里不准备具体写差分数组的解法,参照 [差分数组技巧](https://labuladong.online/algo/data-structure/diff-array/) 的原理,有兴趣的读者可以自己尝试去实现。 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | **基于差分数组的思路,我们可以推导出一种更高效,更优雅的解法**。 133 | 134 | 我们首先把这些会议的时间区间进行投影: 135 | 136 | ![](https://labuladong.online/algo/images/arrange-room/1.jpeg) 137 | 138 | 红色的点代表每个会议的开始时间点,绿色的点代表每个会议的结束时间点。 139 | 140 | 现在假想有一条带着计数器的线,在时间线上从左至右进行扫描,每遇到红色的点,计数器 `count` 加一,每遇到绿色的点,计数器 `count` 减一: 141 | 142 | ![](https://labuladong.online/algo/images/arrange-room/2.jpeg) 143 | 144 | **这样一来,每个时刻有多少个会议在同时进行,就是计数器 `count` 的值,`count` 的最大值,就是需要申请的会议室数量**。 145 | 146 | 对差分数组技巧熟悉的读者一眼就能看出来了,这个扫描线其实就是差分数组的遍历过程,所以我们说这是差分数组技巧衍生出来的解法。 147 | 148 | ## 代码实现 149 | 150 | 那么,如何写代码实现这个扫描的过程呢? 151 | 152 | 首先,对区间进行投影,就相当于对每个区间的起点和终点分别进行排序: 153 | 154 | ![](https://labuladong.online/algo/images/arrange-room/3.jpeg) 155 | 156 | ```java 157 | int minMeetingRooms(int[][] meetings) { 158 | int n = meetings.length; 159 | int[] begin = new int[n]; 160 | int[] end = new int[n]; 161 | // 把左端点和右端点单独拿出来 162 | for(int i = 0; i < n; i++) { 163 | begin[i] = meetings[i][0]; 164 | end[i] = meetings[i][1]; 165 | } 166 | // 排序后就是图中的红点 167 | Arrays.sort(begin); 168 | // 排序后就是图中的绿点 169 | Arrays.sort(end); 170 | 171 | // ... 172 | } 173 | ``` 174 | 175 | 然后就简单了,扫描线从左向右前进,遇到红点就对计数器加一,遇到绿点就对计数器减一,计数器 `count` 的最大值就是答案: 176 | 177 | ```java 178 | class Solution { 179 | public int minMeetingRooms(int[][] meetings) { 180 | int n = meetings.length; 181 | int[] begin = new int[n]; 182 | int[] end = new int[n]; 183 | for(int i = 0; i < n; i++) { 184 | begin[i] = meetings[i][0]; 185 | end[i] = meetings[i][1]; 186 | } 187 | Arrays.sort(begin); 188 | Arrays.sort(end); 189 | 190 | // 扫描过程中的计数器 191 | int count = 0; 192 | // 双指针技巧 193 | int res = 0, i = 0, j = 0; 194 | while (i < n && j < n) { 195 | if (begin[i] < end[j]) { 196 | // 扫描到一个红点 197 | count++; 198 | i++; 199 | } else { 200 | // 扫描到一个绿点 201 | count--; 202 | j++; 203 | } 204 | // 记录扫描过程中的最大值 205 | res = Math.max(res, count); 206 | } 207 | 208 | return res; 209 | } 210 | } 211 | ``` 212 | 213 | 这里使用的是 [双指针技巧](https://labuladong.online/algo/essential-technique/array-two-pointers-summary/),根据 `i, j` 的相对位置模拟扫描线前进的过程。 214 | 215 | 至此,这道题就做完了。当然,这个题目也可以变形,比如给你若干会议,问你 `k` 个会议室够不够用,其实你套用本文的解法代码,也可以很轻松解决。 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 |
225 |
226 | 引用本文的题目 227 | 228 | 安装 [我的 Chrome 刷题插件](https://labuladong.online/algo/intro/chrome/) 点开下列题目可直接查看解题思路: 229 | 230 | | LeetCode | 力扣 | 难度 | 231 | | :----: | :----: | :----: | 232 | | [1235. Maximum Profit in Job Scheduling](https://leetcode.com/problems/maximum-profit-in-job-scheduling/?show=1) | [1235. 规划兼职工作](https://leetcode.cn/problems/maximum-profit-in-job-scheduling/?show=1) | 🔴 | 233 | 234 |
235 |
236 | 237 | 238 | 239 | **_____________** 240 | 241 | 242 | 243 | ![](https://labuladong.online/algo/images/souyisou2.png) -------------------------------------------------------------------------------- /高频面试系列/打印素数.md: -------------------------------------------------------------------------------- 1 | # 如何高效寻找素数 2 | 3 | 4 | 5 | ![](https://labuladong.online/algo/images/souyisou1.png) 6 | 7 | **通知:为满足广大读者的需求,网站上架 [速成目录](https://labuladong.online/algo/intro/quick-learning-plan/),如有需要可以看下,谢谢大家的支持~另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。** 8 | 9 | 10 | 11 | 读完本文,你不仅学会了算法套路,还可以顺便解决如下题目: 12 | 13 | | LeetCode | 力扣 | 难度 | 14 | | :----: | :----: | :----: | 15 | | [204. Count Primes](https://leetcode.com/problems/count-primes/) | [204. 计数质数](https://leetcode.cn/problems/count-primes/) | 🟠 | 16 | 17 | **-----------** 18 | 19 | 20 | 21 | 素数的定义看起来很简单,如果一个数如果只能被 1 和它本身整除,那么这个数就是素数。 22 | 23 | 虽然素数的定义并不复杂,恐怕没多少人真的能把素数相关的算法写得高效。 24 | 25 | 比如力扣第 204 题「计数质数」,让你写这样一个函数: 26 | 27 | ```java 28 | // 返回区间 [2, n) 中有几个素数 29 | int countPrimes(int n) 30 | 31 | // 比如 countPrimes(10) 返回 4 32 | // 因为 2,3,5,7 是素数 33 | ``` 34 | 35 | 你会如何写这个函数?我想大家应该会这样写: 36 | 37 | ```java 38 | int countPrimes(int n) { 39 | int count = 0; 40 | for (int i = 2; i < n; i++) 41 | if (isPrime(i)) count++; 42 | return count; 43 | } 44 | 45 | // 判断整数 n 是否是素数 46 | boolean isPrime(int n) { 47 | for (int i = 2; i < n; i++) 48 | if (n % i == 0) 49 | // 有其他整除因子 50 | return false; 51 | return true; 52 | } 53 | ``` 54 | 55 | 这样写的话时间复杂度 O(n^2),问题很大。**首先你用 `isPrime` 函数来辅助的思路就不够高效;而且就算你要用 `isPrime` 函数,这样写算法也是存在计算冗余的**。 56 | 57 | 先来说下**如果你要判断一个数是不是素数,应该如何写算法**。只需稍微修改一下上面的 `isPrime` 代码中的 for 循环条件: 58 | 59 | ```java 60 | boolean isPrime(int n) { 61 | for (int i = 2; i * i <= n; i++) 62 | ... 63 | } 64 | ``` 65 | 66 | 换句话说,`i` 不需要遍历到 `n`,而只需要到 `sqrt(n)` 即可。为什么呢,我们举个例子,假设 `n = 12`。 67 | 68 | 69 | 70 | 71 | 72 | ```java 73 | 12 = 2 × 6 74 | 12 = 3 × 4 75 | 12 = sqrt(12) × sqrt(12) 76 | 12 = 4 × 3 77 | 12 = 6 × 2 78 | ``` 79 | 80 | 81 | 82 | 可以看到,后两个乘积就是前面两个反过来,反转临界点就在 `sqrt(n)`。 83 | 84 | 换句话说,如果在 `[2,sqrt(n)]` 这个区间之内没有发现可整除因子,就可以直接断定 `n` 是素数了,因为在区间 `[sqrt(n),n]` 也一定不会发现可整除因子。 85 | 86 | 现在,`isPrime` 函数的时间复杂度降为 $O(sqrt(N))$,**但是我们实现 `countPrimes` 函数其实并不需要这个函数**,以上只是希望读者明白 `sqrt(n)` 的含义,因为等会还会用到。 87 | 88 | ## 高效实现 `countPrimes` 89 | 90 | 接下来介绍的方法叫做「素数筛选法」,这个方法是古希腊一位名叫埃拉托色尼的大佬发明的,我们在中学的教课书上见过他的大名,因为他就是第一个通过物体的影子正确计算地球周长的人,被推崇为「地理学之父」。 91 | 92 | 回到正题,素数筛选法的核心思路是和上面的常规思路反着来: 93 | 94 | 首先从 2 开始,我们知道 2 是一个素数,那么 2 × 2 = 4, 3 × 2 = 6, 4 × 2 = 8... 都不可能是素数了。 95 | 96 | 然后我们发现 3 也是素数,那么 3 × 2 = 6, 3 × 3 = 9, 3 × 4 = 12... 也都不可能是素数了。 97 | 98 | Wikipedia 的这个 GIF 很形象: 99 | 100 | ![](https://labuladong.online/algo/images/prime/1.gif) 101 | 102 | 看到这里,你是否有点明白这个排除法的逻辑了呢?先看我们的第一版代码: 103 | 104 | ```java 105 | class Solution { 106 | public int countPrimes(int n) { 107 | boolean[] isPrime = new boolean[n]; 108 | // 将数组都初始化为 true 109 | Arrays.fill(isPrime, true); 110 | 111 | for (int i = 2; i < n; i++) { 112 | if (isPrime[i]) { 113 | // i 的倍数不可能是素数了 114 | for (int j = 2 * i; j < n; j += i) { 115 | isPrime[j] = false; 116 | } 117 | } 118 | } 119 | 120 | int count = 0; 121 | for (int i = 2; i < n; i++) { 122 | if (isPrime[i]) count++; 123 | } 124 | 125 | return count; 126 | } 127 | } 128 | ``` 129 | 130 | 如果上面这段代码你能够理解,那么你已经掌握了整体思路,但是还有两个细微的地方可以优化。 131 | 132 | 首先,回想本文开头介绍的 `isPrime` 素数判定函数,由于因子的对称性,其中的 for 循环只需要遍历 `[2,sqrt(n)]` 就够了。这里也是类似的,我们外层的 for 循环也只需要遍历到 `sqrt(n)`: 133 | 134 | ```java 135 | for (int i = 2; i * i < n; i++) 136 | if (isPrime[i]) 137 | ... 138 | ``` 139 | 140 | 除此之外,很难注意到内层的 for 循环也可以优化。我们之前的做法是: 141 | 142 | ```java 143 | for (int j = 2 * i; j < n; j += i) 144 | isPrime[j] = false; 145 | ``` 146 | 147 | 这样可以把 `i` 的整数倍都标记为 `false`,但是仍然存在计算冗余。 148 | 149 | 比如 `n = 25`,`i = 5` 时算法会标记 5 × 2 = 10,5 × 3 = 15 等等数字,但是这两个数字已经被 `i = 2` 和 `i = 3` 的 2 × 5 和 3 × 5 标记了。 150 | 151 | 我们可以稍微优化一下,让 `j` 从 `i * i` 开始遍历,而不是从 `2 * i` 开始: 152 | 153 | ```java 154 | for (int j = i * i; j < n; j += i) 155 | isPrime[j] = false; 156 | ``` 157 | 158 | 这样,素数计数的算法就高效实现了,其实这个算法有一个名字,叫做 Sieve of Eratosthenes。看下完整的最终代码: 159 | 160 | ```java 161 | class Solution { 162 | public int countPrimes(int n) { 163 | boolean[] isPrime = new boolean[n]; 164 | Arrays.fill(isPrime, true); 165 | for (int i = 2; i * i < n; i++) { 166 | if (isPrime[i]) { 167 | for (int j = i * i; j < n; j += i) { 168 | isPrime[j] = false; 169 | } 170 | } 171 | } 172 | 173 | int count = 0; 174 | for (int i = 2; i < n; i++) { 175 | if (isPrime[i]) count++; 176 | } 177 | 178 | return count; 179 | } 180 | } 181 | ``` 182 | 183 | 184 |
185 | 186 |
187 | 188 | 🌈 代码可视化动画🌈 189 | 190 |
191 |
192 |
193 | 194 | 195 | 196 | **该算法的时间复杂度比较难算**,显然时间跟这两个嵌套的 for 循环有关,其操作数应该是: 197 | 198 | n/2 + n/3 + n/5 + n/7 + ... 199 | = n × (1/2 + 1/3 + 1/5 + 1/7...) 200 | 201 | 括号中是素数的倒数。其最终结果是 $O(N * loglogN)$,有兴趣的读者可以查一下该算法的时间复杂度证明。 202 | 203 | 以上就是素数算法相关的全部内容。怎么样,是不是看似简单的问题却有不少细节可以打磨呀? 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 |
212 |
213 | 引用本文的文章 214 | 215 | - [【强化练习】链表双指针经典习题](https://labuladong.online/algo/problem-set/linkedlist-two-pointers/) 216 | - [一文秒杀所有丑数系列问题](https://labuladong.online/algo/frequency-interview/ugly-number-summary/) 217 | 218 |

219 | 220 | 221 | 222 | 223 |
224 |
225 | 引用本文的题目 226 | 227 | 安装 [我的 Chrome 刷题插件](https://labuladong.online/algo/intro/chrome/) 点开下列题目可直接查看解题思路: 228 | 229 | | LeetCode | 力扣 | 难度 | 230 | | :----: | :----: | :----: | 231 | | [264. Ugly Number II](https://leetcode.com/problems/ugly-number-ii/?show=1) | [264. 丑数 II](https://leetcode.cn/problems/ugly-number-ii/?show=1) | 🟠 | 232 | | - | [剑指 Offer 49. 丑数](https://leetcode.cn/problems/chou-shu-lcof/?show=1) | 🟠 | 233 | 234 |
235 |
236 | 237 | 238 | 239 | **_____________** 240 | 241 | 242 | 243 | ![](https://labuladong.online/algo/images/souyisou2.png) -------------------------------------------------------------------------------- /高频面试系列/缺失和重复的元素.md: -------------------------------------------------------------------------------- 1 | # 如何同时寻找缺失和重复的元素 2 | 3 | 4 | 5 | ![](https://labuladong.online/algo/images/souyisou1.png) 6 | 7 | **通知:为满足广大读者的需求,网站上架 [速成目录](https://labuladong.online/algo/intro/quick-learning-plan/),如有需要可以看下,谢谢大家的支持~另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。** 8 | 9 | 10 | 11 | 读完本文,你不仅学会了算法套路,还可以顺便解决如下题目: 12 | 13 | | LeetCode | 力扣 | 难度 | 14 | | :----: | :----: | :----: | 15 | | [645. Set Mismatch](https://leetcode.com/problems/set-mismatch/) | [645. 错误的集合](https://leetcode.cn/problems/set-mismatch/) | 🟢 | 16 | 17 | **-----------** 18 | 19 | 20 | 21 | 今天就聊一道很看起来简单却十分巧妙的问题,寻找缺失和重复的元素。之前的一篇文章 [常用的位操作](https://labuladong.online/algo/frequency-interview/bitwise-operation/) 中也写过类似的问题,不过这次的和上次的问题使用的技巧不同。 22 | 23 | 这是力扣第 645 题「错误的集合」,我来描述一下这个题目: 24 | 25 | 给一个长度为 `N` 的数组 `nums`,其中本来装着 `[1..N]` 这 `N` 个元素,无序。但是现在出现了一些错误,`nums` 中的一个元素出现了重复,也就同时导致了另一个元素的缺失。请你写一个算法,找到 `nums` 中的重复元素和缺失元素的值。 26 | 27 | ```java 28 | // 返回两个数字,分别是 {dup, missing} 29 | int[] findErrorNums(int[] nums); 30 | ``` 31 | 32 | 比如说输入:`nums = [1,2,2,4]`,算法返回 `[2,3]`。 33 | 34 | 其实很容易解决这个问题,先遍历一次数组,用一个哈希表记录每个数字出现的次数,然后遍历一次 `[1..N]`,看看那个元素重复出现,那个元素没有出现,就 OK 了。 35 | 36 | 但问题是,这个常规解法需要一个哈希表,也就是 O(N) 的空间复杂度。你看题目给的条件那么巧,在 `[1..N]` 的几个数字中恰好有一个重复,一个缺失,**事出反常必有妖**,对吧。 37 | 38 | O(N) 的时间复杂度遍历数组是无法避免的,所以我们可以想想办法如何降低空间复杂度,是否可以在 O(1) 的空间复杂度之下找到重复和缺失的元素呢? 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | ## 思路分析 47 | 48 | 这个问题的特点是,每个元素和数组索引有一定的对应关系。 49 | 50 | 我们现在自己改造下问题,**暂且将 `nums` 中的元素变为 `[0..N-1]`,这样每个元素就和一个数组索引完全对应了,这样方便理解一些**。 51 | 52 | 如果说 `nums` 中不存在重复元素和缺失元素,那么每个元素就和唯一一个索引值对应,对吧? 53 | 54 | 现在的问题是,有一个元素重复了,同时导致一个元素缺失了,这会产生什么现象呢?**会导致有两个元素对应到了同一个索引,而且会有一个索引没有元素对应过去**。 55 | 56 | 那么,如果我能够通过某些方法,找到这个重复对应的索引,不就是找到了那个重复元素么?找到那个没有元素对应的索引,不就是找到了那个缺失的元素了么? 57 | 58 | 那么,如何不使用额外空间判断某个索引有多少个元素对应呢?这就是这个问题的精妙之处了: 59 | 60 | **通过将每个索引对应的元素变成负数,以表示这个索引被对应过一次了**,算法过程如下 GIF 所示: 61 | 62 | ![](https://labuladong.online/algo/images/dupmissing/1.gif) 63 | 64 | 如果出现重复元素 `4`,直观结果就是,索引 `4` 所对应的元素已经是负数了: 65 | 66 | ![](https://labuladong.online/algo/images/dupmissing/2.jpg) 67 | 68 | 对于缺失元素 `3`,直观结果就是,索引 `3` 所对应的元素是正数: 69 | 70 | ![](https://labuladong.online/algo/images/dupmissing/3.jpg) 71 | 72 | 对于这个现象,我们就可以翻译成代码了: 73 | 74 | ```java 75 | int[] findErrorNums(int[] nums) { 76 | int n = nums.length; 77 | int dup = -1; 78 | for (int i = 0; i < n; i++) { 79 | int index = Math.abs(nums[i]); 80 | // nums[index] 小于 0 则说明重复访问 81 | if (nums[index] < 0) 82 | dup = Math.abs(nums[i]); 83 | else 84 | nums[index] *= -1; 85 | } 86 | 87 | int missing = -1; 88 | for (int i = 0; i < n; i++) 89 | // nums[i] 大于 0 则说明没有访问 90 | if (nums[i] > 0) 91 | missing = i; 92 | 93 | return new int[]{dup, missing}; 94 | } 95 | ``` 96 | 97 | 这个问题就基本解决了,别忘了我们刚才为了方便分析,假设元素是 `[0..N-1]`,但题目要求是 `[1..N]`,所以只要简单修改两处地方即可得到原题的答案: 98 | 99 | ```java 100 | class Solution { 101 | public int[] findErrorNums(int[] nums) { 102 | int n = nums.length; 103 | int dup = -1; 104 | for (int i = 0; i < n; i++) { 105 | // 现在的元素是从 1 开始的 106 | int index = Math.abs(nums[i]) - 1; 107 | if (nums[index] < 0) 108 | dup = Math.abs(nums[i]); 109 | else 110 | nums[index] *= -1; 111 | } 112 | 113 | int missing = -1; 114 | for (int i = 0; i < n; i++) 115 | if (nums[i] > 0) 116 | // 将索引转换成元素 117 | missing = i + 1; 118 | 119 | return new int[]{dup, missing}; 120 | } 121 | } 122 | ``` 123 | 124 | 125 |
126 | 127 |
128 | 129 | 🥳 代码可视化动画🥳 130 | 131 |
132 |
133 |
134 | 135 | 136 | 137 | 其实,元素从 1 开始是有道理的,也必须从一个非零数开始。因为如果元素从 0 开始,那么 0 的相反数还是自己,所以如果数字 0 出现了重复或者缺失,算法就无法判断 0 是否被访问过。我们之前的假设只是为了简化题目,更通俗易懂。 138 | 139 | ## 最后总结 140 | 141 | 对于这种数组问题,**关键点在于元素和索引是成对儿出现的,常用的方法是排序、异或、映射**。 142 | 143 | 映射的思路就是我们刚才的分析,将每个索引和元素映射起来,通过正负号记录某个元素是否被映射。 144 | 145 | 排序的方法也很好理解,对于这个问题,可以想象如果元素都被从小到大排序,如果发现索引对应的元素如果不相符,就可以找到重复和缺失的元素。 146 | 147 | 异或运算也是常用的,因为异或性质 `a ^ a = 0, a ^ 0 = a`,如果将索引和元素同时异或,就可以消除成对儿的索引和元素,留下的就是重复或者缺失的元素。可以看看前文 [常用的位运算](https://labuladong.online/algo/frequency-interview/bitwise-operation/),介绍过这种方法。 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 |
156 |
157 | 引用本文的文章 158 | 159 | - [【强化练习】哈希表更多习题](https://labuladong.online/algo/problem-set/hash-table/) 160 | 161 |

162 | 163 | 164 | 165 | 166 |
167 |
168 | 引用本文的题目 169 | 170 | 安装 [我的 Chrome 刷题插件](https://labuladong.online/algo/intro/chrome/) 点开下列题目可直接查看解题思路: 171 | 172 | | LeetCode | 力扣 | 难度 | 173 | | :----: | :----: | :----: | 174 | | [442. Find All Duplicates in an Array](https://leetcode.com/problems/find-all-duplicates-in-an-array/?show=1) | [442. 数组中重复的数据](https://leetcode.cn/problems/find-all-duplicates-in-an-array/?show=1) | 🟠 | 175 | | [448. Find All Numbers Disappeared in an Array](https://leetcode.com/problems/find-all-numbers-disappeared-in-an-array/?show=1) | [448. 找到所有数组中消失的数字](https://leetcode.cn/problems/find-all-numbers-disappeared-in-an-array/?show=1) | 🟢 | 176 | 177 |
178 |
179 | 180 | 181 | 182 | **_____________** 183 | 184 | 185 | 186 | ![](https://labuladong.online/algo/images/souyisou2.png) -------------------------------------------------------------------------------- /高频面试系列/随机权重.md: -------------------------------------------------------------------------------- 1 | # 带权重的随机选择算法 2 | 3 | 4 | 5 | ![](https://labuladong.online/algo/images/souyisou1.png) 6 | 7 | **通知:为满足广大读者的需求,网站上架 [速成目录](https://labuladong.online/algo/intro/quick-learning-plan/),如有需要可以看下,谢谢大家的支持~另外,建议你在我的 [网站](https://labuladong.online/algo/) 学习文章,体验更好。** 8 | 9 | 10 | 11 | 读完本文,你不仅学会了算法套路,还可以顺便解决如下题目: 12 | 13 | | LeetCode | 力扣 | 难度 | 14 | | :----: | :----: | :----: | 15 | | [528. Random Pick with Weight](https://leetcode.com/problems/random-pick-with-weight/) | [528. 按权重随机选择](https://leetcode.cn/problems/random-pick-with-weight/) | 🟠 | 16 | | - | [剑指 Offer II 071. 按权重生成随机数](https://leetcode.cn/problems/cuyjEf/) | 🟠 | 17 | 18 | **-----------** 19 | 20 | 21 | 22 | > [!NOTE] 23 | > 阅读本文前,你需要先学习: 24 | > 25 | > - [前缀和算法技巧](https://labuladong.online/algo/data-structure/prefix-sum/) 26 | > - [二分查找框架详解](https://labuladong.online/algo/essential-technique/binary-search-framework/) 27 | 28 | 写这篇的文章的原因是玩 LOL 手游。我有个朋友抱怨说打排位匹配的队友太菜了,我就说我打排位觉得队友都挺行的啊,好像不怎么坑? 29 | 30 | 朋友意味深长地说了句:一般隐藏分比较高的玩家,排位如果排不到实力相当的队友,就会排到一些菜狗。 31 | 32 | 嗯?我想了几秒钟感觉这小伙子不对劲,他意思是说我隐藏分低,还是说我就是那条菜狗? 33 | 34 | 我立马要求和他开黑打一把,证明我不是菜狗,他才是菜狗。开黑结果这里不便透露,大家猜猜吧。 35 | 36 | 打完之后我就来发文了,因为我对游戏的匹配机制有了一点思考。 37 | 38 | ![](https://labuladong.online/algo/images/random-weight/images.png) 39 | 40 | **所谓「隐藏分」我不知道是不是真的,毕竟匹配机制是所有竞技类游戏的核心环节,想必非常复杂,不是简单几个指标就能搞定的**。 41 | 42 | 但是如果把这个「隐藏分」机制简化,倒是一个值得思考的算法问题:系统如何以不同的随机概率进行匹配? 43 | 44 | 或者简单点说,如何带权重地做随机选择? 45 | 46 | 不要觉得这个很容易,如果给你一个长度为 `n` 的数组,让你从中等概率随机抽取一个元素,你肯定会做,random 一个 `[0, n-1]` 的数字出来作为索引就行了,每个元素被随机选到的概率都是 `1/n`。 47 | 48 | 但假设每个元素都有不同的权重,权重地大小代表随机选到这个元素的概率大小,你如何写算法去随机获取元素呢? 49 | 50 | 力扣第 528 题「按权重随机选择」就是这样一个问题: 51 | 52 | 53 | 54 | 我们就来思考一下这个问题,解决按照权重随机选择元素的问题。 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | ## 解法思路 63 | 64 | 首先回顾一下我们和随机算法有关的历史文章: 65 | 66 | 前文 [设计随机删除元素的数据结构](https://labuladong.online/algo/data-structure/random-set/) 主要考察的是数据结构的使用,每次把元素移到数组尾部再删除,可以避免数据搬移。 67 | 68 | 前文 [谈谈游戏中的随机算法](https://labuladong.online/algo/frequency-interview/random-algorithm/) 讲的是经典的「水塘抽样算法」,运用简单的数学运算,在无限序列中等概率选取元素。 69 | 70 | 前文 [算法笔试技巧](https://labuladong.online/algo/other-skills/tips-in-exam/) 中我还分享过一个巧用概率最大化测试用例通过率的骗分技巧。 71 | 72 | **不过上述旧文并不能解决本文提出的问题,反而是前文 [前缀和技巧](https://labuladong.online/algo/data-structure/prefix-sum/) 加上 [二分搜索详解](https://labuladong.online/algo/essential-technique/binary-search-framework/) 能够解决带权重的随机选择算法**。 73 | 74 | 这个随机算法和前缀和技巧和二分搜索技巧能扯上啥关系?且听我慢慢道来。 75 | 76 | 假设给你输入的权重数组是 `w = [1,3,2,1]`,我们想让概率符合权重,那么可以抽象一下,根据权重画出这么一条彩色的线段: 77 | 78 | ![](https://labuladong.online/algo/images/random-weight/1.jpeg) 79 | 80 | 如果我在线段上面随机丢一个石子,石子落在哪个颜色上,我就选择该颜色对应的权重索引,那么每个索引被选中的概率是不是就是和权重相关联了? 81 | 82 | **所以,你再仔细看看这条彩色的线段像什么?这不就是 [前缀和数组](https://labuladong.online/algo/data-structure/prefix-sum/) 嘛**: 83 | 84 | ![](https://labuladong.online/algo/images/random-weight/2.jpeg) 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 那么接下来,如何模拟在线段上扔石子? 93 | 94 | 当然是随机数,比如上述前缀和数组 `preSum`,取值范围是 `[1, 7]`,那么我生成一个在这个区间的随机数 `target = 5`,就好像在这条线段中随机扔了一颗石子: 95 | 96 | ![](https://labuladong.online/algo/images/random-weight/3.jpeg) 97 | 98 | 还有个问题,`preSum` 中并没有 5 这个元素,我们应该选择比 5 大的最小元素,也就是 6,即 `preSum` 数组的索引 3: 99 | 100 | ![](https://labuladong.online/algo/images/random-weight/4.jpeg) 101 | 102 | **如何快速寻找数组中大于等于目标值的最小元素?[二分搜索算法](https://labuladong.online/algo/essential-technique/binary-search-framework/) 就是我们想要的**。 103 | 104 | 到这里,这道题的核心思路就说完了,主要分几步: 105 | 106 | 1、根据权重数组 `w` 生成前缀和数组 `preSum`。 107 | 108 | 2、生成一个取值在 `preSum` 之内的随机数,用二分搜索算法寻找大于等于这个随机数的最小元素索引。 109 | 110 | 3、最后对这个索引减一(因为前缀和数组有一位索引偏移),就可以作为权重数组的索引,即最终答案: 111 | 112 | ![](https://labuladong.online/algo/images/random-weight/5.jpeg) 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | ## 解法代码 121 | 122 | 上述思路应该不难理解,但是写代码的时候坑可就多了。 123 | 124 | 要知道涉及开闭区间、索引偏移和二分搜索的题目,需要你对算法的细节把控非常精确,否则会出各种难以排查的 bug。 125 | 126 | 下面来抠细节,继续前面的例子: 127 | 128 | ![](https://labuladong.online/algo/images/random-weight/3.jpeg) 129 | 130 | 就比如这个 `preSum` 数组,你觉得随机数 `target` 应该在什么范围取值?闭区间 `[0, 7]` 还是左闭右开 `[0, 7)`? 131 | 132 | 都不是,应该在闭区间 `[1, 7]` 中选择,**因为前缀和数组中 0 本质上是个占位符**,仔细体会一下: 133 | 134 | ![](https://labuladong.online/algo/images/random-weight/6.jpeg) 135 | 136 | 所以要这样写代码: 137 | 138 | ```java 139 | int n = preSum.length; 140 | // target 取值范围是闭区间 [1, preSum[n - 1]] 141 | int target = rand.nextInt(preSum[n - 1]) + 1; 142 | ``` 143 | 144 | 接下来,在 `preSum` 中寻找大于等于 `target` 的最小元素索引,应该用什么品种的二分搜索?搜索左侧边界的还是搜索右侧边界的? 145 | 146 | 实际上应该使用搜索左侧边界的二分搜索: 147 | 148 | ```java 149 | // 搜索左侧边界的二分搜索 150 | int left_bound(int[] nums, int target) { 151 | if (nums.length == 0) return -1; 152 | int left = 0, right = nums.length; 153 | while (left < right) { 154 | int mid = left + (right - left) / 2; 155 | if (nums[mid] == target) { 156 | right = mid; 157 | } else if (nums[mid] < target) { 158 | left = mid + 1; 159 | } else if (nums[mid] > target) { 160 | right = mid; 161 | } 162 | } 163 | return left; 164 | } 165 | ``` 166 | 167 | 前文 [二分搜索详解](https://labuladong.online/algo/essential-technique/binary-search-framework/) 着重讲了数组中存在目标元素重复的情况,没仔细讲目标元素不存在的情况,这里补充一下。 168 | 169 | **当目标元素 `target` 不存在数组 `nums` 中时,搜索左侧边界的二分搜索的返回值可以做以下几种解读**: 170 | 171 | 1、返回的这个值是 `nums` 中大于等于 `target` 的最小元素索引。 172 | 173 | 2、返回的这个值是 `target` 应该插入在 `nums` 中的索引位置。 174 | 175 | 3、返回的这个值是 `nums` 中小于 `target` 的元素个数。 176 | 177 | 比如在有序数组 `nums = [2,3,5,7]` 中搜索 `target = 4`,搜索左边界的二分算法会返回 2,你带入上面的说法,都是对的。 178 | 179 | 所以以上三种解读都是等价的,可以根据具体题目场景灵活运用,显然这里我们需要的是第一种。 180 | 181 | 综上,我们可以写出最终解法代码: 182 | 183 | ```java 184 | class Solution { 185 | // 前缀和数组 186 | private int[] preSum; 187 | private Random rand = new Random(); 188 | 189 | public Solution(int[] w) { 190 | int n = w.length; 191 | // 构建前缀和数组,偏移一位留给 preSum[0] 192 | preSum = new int[n + 1]; 193 | preSum[0] = 0; 194 | // preSum[i] = sum(w[0..i-1]) 195 | for (int i = 1; i <= n; i++) { 196 | preSum[i] = preSum[i - 1] + w[i - 1]; 197 | } 198 | } 199 | 200 | public int pickIndex() { 201 | int n = preSum.length; 202 | // Java 的 nextInt(n) 方法在 [0, n) 中生成一个随机整数 203 | // 再加一就是在闭区间 [1, preSum[n - 1]] 中随机选择一个数字 204 | int target = rand.nextInt(preSum[n - 1]) + 1; 205 | // 获取 target 在前缀和数组 preSum 中的索引 206 | // 别忘了前缀和数组 preSum 和原始数组 w 有一位索引偏移 207 | return left_bound(preSum, target) - 1; 208 | } 209 | 210 | // 搜索左侧边界的二分搜索 211 | private int left_bound(int[] nums, int target) { 212 | int left = 0, right = nums.length; 213 | while (left < right) { 214 | int mid = left + (right - left) / 2; 215 | if (nums[mid] == target) { 216 | right = mid; 217 | } else if (nums[mid] < target) { 218 | left = mid + 1; 219 | } else if (nums[mid] > target) { 220 | right = mid; 221 | } 222 | } 223 | return left; 224 | } 225 | } 226 | ``` 227 | 228 | 有了之前的铺垫,相信你能够完全理解上述代码,这道随机权重的题目就解决了。 229 | 230 | 经常有读者留言调侃,每次都是看我的文章「云刷题」,看完就会了,也不用亲自动手刷了。 231 | 232 | 但我想说的是,很多题目思路一说就懂,但是深入一些的话很多细节都可能有坑,本文讲的这道题就是一个例子,所以还是建议多实践,多总结。 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 |
243 |
244 | 引用本文的文章 245 | 246 | - [用数组加强哈希表(ArrayHashMap)](https://labuladong.online/algo/data-structure-basic/hashtable-with-array/) 247 | - [谈谈游戏中的随机算法](https://labuladong.online/algo/frequency-interview/random-algorithm/) 248 | 249 |

250 | 251 | 252 | 253 | 254 | 255 | **_____________** 256 | 257 | 258 | 259 | ![](https://labuladong.online/algo/images/souyisou2.png) --------------------------------------------------------------------------------