
数据结构与算法
代码拌饭饭更香
早日暴富
展开
-
回溯算法:计算24点牌
回溯算法:计算24点牌1.将4个整数放入数组中2.在数组中取两个数字的排列,共有 P(4,2) 种排列。对每一个排列,对 – * / 每一个运算符,3.根据此排列的两个数字和运算符,计算结果4.改表数组:将此排列的两个数字从数组中去除掉,将 2.1.1 计算的结果放入数组中5.对新的数组,重复步骤 2恢复数组:将此排列的两个数字加入数组中,将 2.1.1 计算的结果从数组中去除掉可见这是一个递归过程。步骤 2 就是递归函数。当数组中只剩下一个数字的时候,这就是表达式的最终结果,此时递归结束。原创 2021-03-12 09:33:04 · 734 阅读 · 2 评论 -
贪心算法:分发糖果,一道经典易错的题目
贪心算法:分发糖果那么本题我采用了两次贪心的策略:一次是从左到右遍历,只比较右边孩子评分比左边大的情况。一次是从右到左遍历,只比较左边孩子评分比右边大的情况。注意实现细节!class Solution {public: int candy(vector<int>& ratings) { //贪心算法 //先从左往右遍历 //再从右往左遍历 //初始化给每个人一块饼干 vector<原创 2021-03-08 16:55:22 · 188 阅读 · 0 评论 -
贪心算法:跳跃游戏
贪心算法:跳跃游戏思路:第一反应是回溯问题,不断穷举nums【i】可能经过的路线,但是很遗憾,运行超时了代码如下,也算是提供思路吧:class Solution {public: bool canJump(vector<int>& nums) { int startIndex = 0; bool flag = false; backtrack(nums, startIndex, flag); return原创 2021-03-06 12:37:38 · 434 阅读 · 3 评论 -
贪心算法:买卖股票的最佳时机II
贪心算法:买卖股票的最佳时机II思路:我们采用贪心算法,计算每天的利润,然后选取正利润即可代码:class Solution {public: int maxProfit(vector<int>& prices) { int maxSum = 0; for(int i = 1; i < prices.size(); i++) { maxSum += max(prices[i] - prices原创 2021-03-06 10:43:54 · 112 阅读 · 0 评论 -
回溯算法:N皇后问题
回溯算法:N皇后问题N皇后的约数条件:不能同行不能同列不能同斜线图解:这样一看,N皇后问题就清晰多了void backtracking(参数) { if (row == n) { 存放结果; return; } for (节点展开) { if(isValid(row, col, chessboard, n)) { //设置皇后转载 2021-03-03 15:53:46 · 138 阅读 · 1 评论 -
回溯算法:排列问题II,去重方法全归纳!
回溯算法:排列问题II思路,这道题也是需要去重,但和之前的去重又有些不同,对去重进行一下整理:一般来说:组合问题和排列问题是在树形结构的叶子节点上收集结果,而子集问题就是取树上所有节点的结果1.组合数问题:i > startIndex && nums[i] == nums[i - 1] 这是对同一树层的相邻且相同的元素进行去重,比如【1,2 ,3, 3,3,4】,对于一树枝上的相同元素无需去重2. 递增子序列:利比上面稍微复杂,相同元素并没有相邻了,因此借用set进行去重,u原创 2021-03-03 12:53:19 · 775 阅读 · 3 评论 -
回溯算法:全排列问题
回溯算法:全排列问题思路:利用一个数组进行去重class Solution {public: vector<vector<int>> res; vector<int> path; vector<int> use; vector<vector<int>> permute(vector<int>& nums) { int step = 0; use.原创 2021-03-02 22:26:36 · 145 阅读 · 0 评论 -
回溯算法:递增子序列,弄清去重本质!
回溯算法:递增子序列,去重从此不再困难!思路:第一感觉和之前去重不是一样嘛?恭喜你上当了!输入:[1,2,3,4,5,6,7,8,9,10,1,1,1,1,1]会发现[1,1],[1,1,1],[1,1,1,1],[1,1,1,1,1]重复出现了两次,问题就显现了,因为:之前去重是单层节点相邻元素之间的去重,因此,排序后去重if(i > startIndex && nums[i] == nums[i - 1]),但是现在我们不能将其进行排序,所有我们要采用第二种方法去重:去除同一原创 2021-03-02 21:44:57 · 380 阅读 · 1 评论 -
回溯算法:子集II
回溯算法:子集II思路:该题为子集问题,与之前“组合总和问题II”的去重思想一致,即相同一层不能有相同的元素,因此去重逻辑:if(i > startIdex && nums[i] == nums[i - 1])不变,注意要先排序,将相同元素放在一起class Solution {public: vector<vector<int>> res; vector<int> path; vector<vector<原创 2021-03-02 20:27:29 · 92 阅读 · 0 评论 -
回溯算法:子集
回溯算法:子集思路:简单的回溯,认识本质之后,这就是一道模板题class Solution {public: vector<vector<int>> res; vector<int> path; vector<vector<int>> subsets(vector<int>& nums) { int startIndex = 0; res.push_back(pat原创 2021-03-01 17:17:16 · 86 阅读 · 0 评论 -
回溯算法:复原IP
回溯算法:复原IP思路:与上一篇:回溯算法:分割回文串异曲同工之妙,同样是切割字符串的思想,本体在剪枝方面可以进一步优化,当有不符合IP的字符串出现时,可以直接跳过本层所有循环,即break,但分割回文串则不可以,因为你不知道本层中加入下一个字符后是否可以构成回文串,因此不能跳出本层循环,即循环跳出条件为continueclass Solution {public: vector<string> res; string path; vector<string原创 2021-03-01 17:03:44 · 91 阅读 · 0 评论 -
回溯算法:分割回文串
回溯算法:分割回文串在for (int i = startIndex; i < s.size(); i++)循环中,我们 定义了起始位置startIndex,那么 [startIndex, i] 就是要截取的子串。class Solution {public: vector<vector<string>> res; vector<string> path; vector<vector<string>> par原创 2021-02-25 17:14:16 · 138 阅读 · 0 评论 -
回溯算法:组合总和问题一网打尽
回溯算法:组合问题I,II,III组合问题I回溯+剪枝代码如下:剪枝过程:i + (k - path.size()) <= n + 1,数组为单调递增的,当前位置不成立后,后序数字也无需进行比较了class Solution {public: vector<vector<int>> res; vector<int> path; vector<vector<int>> combine(int n, int k)原创 2021-02-25 14:19:54 · 1021 阅读 · 0 评论 -
回溯算法:电话号码的字母组合
回溯算法:电话号码的字母组合个人理解:将每一层展开,将下一次节点的开始位置传入递归中class Solution {public: vector<string> combinations; string combination; unordered_map<char,string> phoneMap { {'2', "abc"}, {'3', "def"}, {'4', "原创 2021-02-24 17:42:47 · 193 阅读 · 0 评论 -
栈与队列:TOP-K问题:前 K 个高频元素
栈与队列:TOP-K问题:前 K 个高频元素解法一:粗暴排序法最简单粗暴的思路就是 使用排序算法对元素按照频率由高到低进行排序,然后再取前 kk 个元素。以下十种排序算法,任你挑选!可以发现,使用常规的诸如 冒泡、选择、甚至快速排序都是不满足题目要求,它们的时间复杂度都是大于或者等于 O(n logn)O(nlogn),而题目要求算法的时间复杂度必须优于 O(n log n)O(nlogn)。解法二:借助 哈希表 来建立数字和其出现次数的映射,遍历一遍数组统计元素的频率维护一个元素数原创 2021-02-23 21:46:37 · 289 阅读 · 0 评论 -
Priority_Queue优先级队列的自我实现
优先级队列的自我实现代码如下:Priority_Queue.h文件:#pragma once#include <vector>namespace bite{ template<class T, class Container = std::vector<T>, class Com = std::less<T>> class priority_queue { public: priority_queue() {} templ原创 2021-02-23 21:20:35 · 163 阅读 · 0 评论 -
栈与队列:单调队列解决滑动窗口最大值
栈与队列:单调队列解决滑动窗口最大值设计单调队列的时候,pop,和push操作要保持如下规则:pop(value):如果窗口移除的元素value等于单调队列的出口元素,那么队列弹出元素,否则不用任何操作push(value):如果push的元素value大于入口元素的数值,那么就将队列入口的元素弹出,直到push元素的数值小于等于队列入口元素的数值为止以题目示例为例,输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3单调队列:3,-1单调队列:3,-1,-3原创 2021-02-23 15:25:52 · 373 阅读 · 0 评论 -
栈与队列:逆波兰表达式
栈与队列:逆波兰表达式思路:利用stringstream将字符串转化为数字,将计算结果入栈,注意:result = num2 / num1;result = num2 - num1num2与num1的顺序class Solution {public: int evalRPN(vector<string>& tokens) { stack<int> s; int size = tokens.size(); i原创 2021-02-22 15:37:13 · 101 阅读 · 0 评论 -
栈与队列:删除字符串中的所有相邻重复项
栈与队列:删除字符串中的所有相邻重复项class Solution {public: string removeDuplicates(string S) { stack<int> st; int size = S.size(); string res; for(int i = 0; i < size; i++) { if(st.empty()) {原创 2021-02-22 15:07:55 · 180 阅读 · 0 评论 -
栈与队列:有效的括号
栈与队列:括号匹配问题class Solution {public: bool isValid(string s) { if(s.empty()) return true; stack<char> _stack; for(int i=0;i<s.size();i++) { if(s[i]=='(' || s[i]=='[' || s[i]=='{')原创 2021-02-22 14:57:54 · 99 阅读 · 0 评论 -
栈与队列:用队列实现栈
栈与队列:用队列实现栈class MyStack {public: /** Initialize your data structure here. */ queue<int> qIn; queue<int> qOut; MyStack() { } /** Push element x onto stack. */ void push(int x) { qIn.push(x); }原创 2021-02-22 14:54:29 · 71 阅读 · 0 评论 -
栈与队列:栈实现队列
栈与队列:栈实现队列class MyQueue {public: stack<int> stIn; stack<int> stOut; /** Initialize your data structure here. */ MyQueue() { } /** Push element x to the back of queue. */ void push(int x) { stIn.push(原创 2021-02-21 16:46:25 · 73 阅读 · 0 评论 -
字符串:KMP算法,重复的子字符串
字符串:KMP算法,重复的子字符串普通的方法,双指针逐个比较:class Solution {public: bool repeatedSubstringPattern(string s) { for(int i = 1; i * 2 <= s.size(); i++) { if(s.size() % i == 0) { int begin1 = 0;原创 2021-02-21 14:10:57 · 644 阅读 · 1 评论 -
字符串:KMP算法,实现strStr()
字符串:KMP算法,实现strStr()代码:class Solution {public: int strStr(string haystack, string needle) { if(needle.size() == 0) return 0; int next[needle.size()]; getNext(next, needle); int j = 0; for(int i = 0; i原创 2021-02-20 17:43:09 · 389 阅读 · 0 评论 -
字符串:反转字符串里的单词
字符串:反转字符串里的单词stringstream对空格处理的妙用:class Solution {public: string reverseWords(string s) { stringstream st; st << s; string tmp; string ans; while(st >> tmp) { ans = ' ' + tmp +原创 2021-02-20 15:10:29 · 83 阅读 · 0 评论 -
字符串:反转字符串I,II,III
反转字符串I简单的双指针class Solution {public: void reverseString(vector<char>& s) { int begin = 0; int end = s.size() - 1; while(begin < end) { swap(s[begin], s[end]); begin++;原创 2021-02-18 17:19:54 · 241 阅读 · 0 评论 -
字符串:替换空格
字符串:替换空格普通的方法:class Solution {public: string replaceSpace(string s) { int count = 0; int oldSize = s.size(); for(auto &k : s) { if(k ==' ') count++; } s.resize(oldSize + 2原创 2021-02-18 16:54:52 · 150 阅读 · 0 评论 -
哈希:【两数之和】与【三数之和】与【四数之和】
哈希:两数之和与三数之和两数之和:利用unordered_map解决问题:class Solution {public: vector<int> twoSum(vector<int>& nums, int target) { unordered_map<int, int> hashtable; for (int i = 0; i < nums.size(); ++i) { auto i原创 2021-02-16 16:50:36 · 169 阅读 · 1 评论 -
哈希:赎金信
哈希:赎金信本题判断第一个字符串ransom能不能由第二个字符串magazines里面的字符构成,但是这里需要注意两点。第一点“为了不暴露赎金信字迹,要从杂志上搜索各个需要的字母,组成单词来表达意思” 这里说明杂志里面的字母不可重复使用。第二点 “你可以假设两个字符串均只含有小写字母。” 说明只有小写字母,这一点很重要class Solution {public: bool canConstruct(string ransomNote, string magazine) {原创 2021-02-16 15:31:59 · 136 阅读 · 2 评论 -
哈希:四数相加
哈希:四数相加首先定义 一个unordered_map,key放a和b两数之和,value 放a和b两数之和出现的次数。遍历大A和大B数组,统计两个数组元素之和,和出现的次数,放到map中。定义int变量count,用来统计a+b+c+d = 0 出现的次数。在遍历大C和大D数组,找到如果 0-(c+d) 在map中出现过的话,就用count把map中key对应的value也就是出现次数统计出来。最后返回统计值 count 就可以了class Solution {public:原创 2021-02-16 15:08:53 · 178 阅读 · 0 评论 -
红黑树:节点插入详解及其红黑树自我实现
红黑树:节点插入详解及其红黑树自我实现红黑树的四个性质:每个结点不是红色就是黑色根节点是黑色的如果一个节点是红色的,则它的两个孩子结点是黑色的对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点每个叶子结点都是黑色的(此处的叶子结点指的是空结点)红黑树节点的定义:// 红黑树节点的定义template<class T>struct RBTreeNode{ RBTreeNode(const T& x = T(), Color c = R原创 2021-01-28 18:19:19 · 1837 阅读 · 7 评论 -
平衡二叉树-的四种旋转调整(代码,图解)
平衡二叉树-的四种旋转调整(代码,图解)1.右单旋:新插入节点插入在较高左子树的左侧(左左右),插入新节点二十:1.修改parent和curLR的孩子指针域parent->left = curLR;// 避免左单支的场景:subLR是nullptrif (subLR) curLR->parent = parent;2.修改parent和curL的指针域curL->right = parent;3.处理旋转之前parent的双亲的孩子// 因为pare原创 2021-01-28 16:40:34 · 3957 阅读 · 7 评论 -
二叉搜索树:修剪二叉搜索树
二叉搜索树:修建二叉搜索树第一反应是重构,看来别人的解答发现,其实不用重构那么复杂。 TreeNode* trimBST(TreeNode* root, int low, int high) { if(root == nullptr) return root; if(root->val < low) { TreeNode *right = trimBST(root->right, low, hi原创 2021-01-24 16:03:18 · 145 阅读 · 1 评论 -
二叉搜索树:二叉搜索树的最近公共祖先
二叉搜索树:二叉搜索树的最近公共祖先和二叉树:公共祖先问题不同,普通二叉树求最近公共祖先需要使用回溯,从底向上来查找,二叉搜索树就不用了,因为搜索树有序(相当于自带方向),那么只要从上向下遍历就可以了。那么我们可以采用前序遍历(其实这里没有中节点的处理逻辑,遍历顺序无所谓了)。TreeNode* traversal(TreeNode* cur, TreeNode* p, TreeNode* q) { if (cur == NULL) return cur;原创 2021-01-24 15:24:36 · 207 阅读 · 0 评论 -
二叉搜索树:二叉搜索树的插入操作
二叉搜索树:二叉搜索树的插入操作遇到空节点就插入节点就可以了。TreeNode* insertIntoBST(TreeNode* root, int val) { if(root == NULL) { TreeNode *node = new TreeNode(val); return node; } //如何通过递归函数返回值完成了新加入节点的父子关系赋值操作? //下一层将加入节点返回,本层用r原创 2021-01-24 15:16:57 · 320 阅读 · 0 评论 -
二叉搜索树:删除二叉搜索树中的节点
二叉搜索树:删除二叉搜索树中的节点这里就把平衡二叉树中删除节点遇到的情况都搞清楚。第一种情况:没找到删除的节点,遍历到空节点直接返回了找到删除的节点第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点第三种情况:删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点第四种情况:删除节点的右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点第五种情况:左右孩子节点都不为空,则将删除节点的左子树头结点(左孩子)放到删除节点的右子树的最左原创 2021-01-24 15:12:56 · 369 阅读 · 0 评论 -
二叉树:寻找二叉搜索树的众数
501. 二叉搜索树中的众数易错点:众数有可能不止一个!如果不是二叉搜索树,是普通的树:这个树都遍历了,用map统计频率把统计的出来的出现频率(即map中的value)排个序取前面高频的元素class Solution {public: vector<int> findMode(TreeNode* root) { unordered_map<int, int> map; // key:元素,value:出现频率原创 2021-01-22 16:31:08 · 495 阅读 · 1 评论 -
二叉树:递归函数什么时候需要返回值?
二叉树:递归函数什么时候需要返回值?700. 二叉搜索树中的搜索当初学数据结构的时候也弄不清楚,今天看到一句话很好的解释了:「如果需要搜索整颗二叉树,那么递归函数就不要返回值,如果要搜索其中一条符合条件的路径,递归函数就需要返回值,因为遇到符合条件的路径了就要及时返回。」比如:他并非要遍历全部的二叉树,而是遍历到2就返回了,并非遍历到了全部二叉树.因此,代码如下class Solution {public: TreeNode* searchBST(TreeNode* root, i原创 2021-01-21 17:02:20 · 1322 阅读 · 2 评论 -
二叉树:最大二叉树,习惯导致的一个致命的错误
二叉树:最大二叉树,小小的问题也会致命题目不难,但我犯了一个错误并且检查了半天才发现,特此记录下:错误:class Solution {public: int maxIndex(vector<int>& nums, int left, int right)//找到数组的最大值 { int maxValue = 0; int maxIndex = 0; for(int i = left; i < ri原创 2021-01-19 17:31:56 · 461 阅读 · 0 评论 -
二叉树:路径总和II,回溯优化的一些小收获
二叉树:路径总和II,回溯的一些个人理解将target值在当前进行改变,回溯到改层是taget值未被改变: targetSum -= root->val; if(!root->left && !root->right && targetSum == 0) { result.push_back(path); } dfs(root->left, targetSu原创 2021-01-19 15:40:48 · 505 阅读 · 0 评论