算法
哎呦,帅小伙哦
这个作者很懒,什么都没留下…
展开
-
LeetCode 334 递增的三元子序列
【代码】LeetCode 334 递增的三元子序列。原创 2024-07-19 18:10:02 · 158 阅读 · 1 评论 -
算法导论线性时间排序——桶排序
leetcode原创 2022-10-05 23:19:58 · 111 阅读 · 0 评论 -
算法导论——线性排序(一)计数排序
每日一题原创 2022-09-19 22:55:10 · 132 阅读 · 0 评论 -
算法导论 ——分治中求解递归式的三种方法
分治原创 2022-09-17 20:51:33 · 1041 阅读 · 0 评论 -
LeetCode 57 插入区间
每日一题原创 2022-09-11 16:16:44 · 127 阅读 · 0 评论 -
LeetCode 679 24点游戏
分析递归回溯,judge函数的含义是对cards中的数据做满足题目的操作是否可以得到24(添加cards.size() - 1个运算符),有顺序的取出两个数进行操作,然后把这两个数操作的结果放到新的vector里面。递归调用judge。面试高频题代码class Solution {public: bool judgePoint24(vector<int>& cards) { vector<double> vec(cards.begi..原创 2021-08-28 11:17:11 · 116 阅读 · 0 评论 -
判断数组中超过一半的数
分析常见面试题,排序的话复杂度太高,可以通过一个计数器nTimes来辅助。代码int findHalfMaxValue(int[] numb){ int length=numb.length; int nTimes,i,value; nTimes = 0; for(i=0;i<length;i++){ if(nTimes==0){ value=numb[i]; .原创 2021-09-13 16:45:39 · 142 阅读 · 0 评论 -
KMP算法
描述查找字符串T中有多少个字符串S,返回个数。KMP算法的改进,把next数组加一个位置。当遍历到这个位置的时候,个数加一。代码class Solution {public: /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * 计算模板串S在文本串T中出现了多少次 * @param S string字符串 模板串 * @param T string字符串 文本串 * @return in.原创 2021-09-01 12:36:55 · 64 阅读 · 0 评论 -
数组中只出现一次的数
描述一个数组中只有一个数出现1次,其余的都出现k次,找出这个数。代码class Solution {public: /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param arr intvector * @param k int * @return int */ int foundOnceNumber(vector<int>& a.原创 2021-08-31 09:36:39 · 67 阅读 · 0 评论 -
最大无重复子数组
问题描述给定一个数组arr,返回arr的最长无重复元素子数组的长度,无重复指的是所有数字都不相同。子数组是连续的,比如[1,3,5,7,9]的子数组有[1,3],[3,5,7]等等,但是[1,3,7]不是子数组。代码class Solution {public: /** * * @param arr int整型vector the array * @return int整型 */ int maxLength(vector<int&.原创 2021-08-28 21:30:41 · 273 阅读 · 0 评论 -
贪心算法
什么是贪心算法?贪心算法可以认为是动态规划算法的特例,相比动态规划,使用贪心算法需要满足更多的条件,但是效率比动态规划要高。比如说一个算法使用暴力解法需要指数级时间,如果能使用动态规划消除重叠子问题,就可以降到多项式级别的时间,如果满足贪心选择性质,那么可以进一步降低时间复杂度,达到线性级别时间复杂度。什么是贪心选择性质呢?简单说就是:每一步都做出一个局部最优的选择,最终的结果就是全局最优。LeetCode 435题就是一个典型的贪心的题目,可以先按vector的第二个元素升序。然后就转化成了比较好理解原创 2021-05-22 15:40:51 · 100 阅读 · 1 评论 -
LeetCode 518 零钱兑换 II
分析这道题是一个完全背包的题目,dp[i][j]的定义如下:若只使用前i个物品,当背包容量为j时,有dp[i][j]种方法可以装满背包。代码class Solution {public: int change(int amount, vector<int>& coins) { int m = coins.size(); vector<vector<int>> dp(m + 1, vector(amount + 1.原创 2021-05-22 13:02:27 · 78 阅读 · 0 评论 -
0-1背包问题
问题描述:给你一个可装载重量为W的背包和N个物品,每个物品有重量和价值两种属性。其中第i个物品的重量是wt[i],价值为val[i],现在让你用这个背包装物品,最多能装的价值是多少?这个问题是一个典型的动态规划的题目,所需要做的:第一步:明确两点,状态和选择先说状态,如何才能描述一个问题局面?只要给定几个可选物品和一个背包的容量限制,就形成了一个背包问题,所以状态有两个,就是(背包容量)和(可选择的物品)。对于选择就是把东西放进背包或者不放进背包。for 状态1 in 状态1的所有取值 for 状原创 2021-05-21 16:49:30 · 109 阅读 · 0 评论 -
LeetCode 516 最长回文子序列
分析dp数组的定义时,在子串s[i…j]中,最长回文子序列的长度为dp[i][j]。找状态转移需要归纳思维,说白了就是如何从已知的结果推出未知的部分。想求dp[i][j],假设你知道了子问题dp[i+1][j-1]的结果(s[i+1…j - 1]中最长回文子序列的长度)。这时候当s[i] == s[j]时 dp[i][j] = dp[i+1][j-1] + 2;当s[i] != s[j]时,dp[i][j] = max{dp[i + 1][j], dp[i][j - 1]}这个状态转移方程画画图就可以.原创 2021-05-20 22:14:27 · 126 阅读 · 0 评论 -
LeetCode 773 滑动谜题
分析求最小步数的问题一般都是使用BFS,但是这道题目是一个二维的2*3的数组,将二维数组放到队列里比较复杂,这个题可以将二维的问题转化成字符串,重点学习neighbor数组的作用。这里它可以把二维的邻居映射成一维的邻居。代码class Solution {public: int slidingPuzzle(vector<vector<int>>& board) { int m = 2, n = 3; string start.原创 2021-05-18 22:25:40 · 76 阅读 · 0 评论 -
LeetCode 752 打开转盘锁
分析BFS的题目,这道题搞懂,基本上BFS的题目就没啥问题了。如果我们不管所有的限制条件,不管deadends和target的限制,就思考一个问题:如何让你设计一个算法,穷举所有可能的密码组合,怎么做?很简单,使用穷举,再简单一点,如果你只转一下锁,有几种可能?总共有4个位置,每个位置可以向上转,也可以向下转,也就是有8种。也就是转一次可以出多少种结果,思考从“0000”转2次可以有多少种结果。到这来应该有解决这个问题的思路了。但是需要注意的是,可能需要进行去重,比如“0000”转一次可能是“1000”.原创 2021-05-18 16:55:09 · 72 阅读 · 0 评论 -
回溯算法
解决一个回溯问题,实际就是一个决策树的遍历过程。只需要思考3个问题:1)路径:也就是已经做出的选择2)选择列表:也就是你当前可以做的选择3)结束条件:也就是到达决策树底层,无法再做选择的条件回溯算法的通用框架如下:result = []def backtrack(路径,选择列表): if 满足结束条件: result.add(路径) return for 选择 in 选择列表: 做选择 backtrack(路径, 选择列表); 撤销选择其核心就是for循环里面的递归原创 2021-05-16 20:11:48 · 107 阅读 · 0 评论 -
LFU算法的实现
分析我们定义两个哈希表,第一个 freq_table 以频率 freq 为索引,每个索引存放一个双向链表,这个链表里存放所有使用频率为 freq 的缓存,缓存里存放三个信息,分别为键 key,值 value,以及使用频率 freq。第二个 key_table 以键值 key 为索引,每个索引存放对应缓存在 freq_table 中链表里的内存地址,这样我们就能利用两个哈希表来使得两个操作的时间复杂度均为 O(1)。同时需要记录一个当前缓存最少使用的频率 minFreq,这是为了删除操作服务的。对于 g.原创 2021-05-16 11:54:19 · 316 阅读 · 0 评论 -
LRU算法的实现
分析LeetCode 146就是实现一个LRU算法,LRU算法的原理不再记录。LRU算法的实现的核心数据结构是哈希链表,就是双向链表和哈希表的结合体。LRU算法需要满足下面3个条件。1)cache中的元素必须是有时序的,以区分最近使用的和久未使用的数据,当容量满之后要删除最久未使用的那个元素腾出位置 ;2)我们要在cache中快速找某个key是否存在并得到value;3) 每次访问cache中的某个key,需要将这个元素变为最近使用的,也就是说cache要支持在任意位置快速插入和删除元素。哈希链表可以满.原创 2021-05-14 23:51:03 · 483 阅读 · 0 评论 -
LeetCode 215 数组中的第K个最大元素
分析维护一个小根堆,当堆的大小大于K的时候,就把堆顶元素pop。时间复杂度是O(N*logK),这个堆的作用就相当于一个筛子,把数组中前K大的数留下,堆顶元素即为第K大元素。代码class Solution {public: int findKthLargest(vector<int>& nums, int k) { priority_queue<int, vector<int>, greater<int>> que.原创 2021-05-14 16:19:27 · 76 阅读 · 0 评论 -
分治算法
回溯、分治、动态规划可以划分为一类,因为它们都会涉及递归。1)回溯算法就是一种简单粗暴的算法技巧,说白了就是一个暴力穷举算法,就考你会不会漏掉或者多算某些情况。2)动态规划是一类算法问题,肯定是让你求最值的。因为动态规划问题拥有最优子结构,可以通过状态转移方程从最小规模的子问题最优解推导出最大规模问题的最优解。3)分治算法,可以认为是一种算法思想,通过将原有问题分解成小规模的子问题,然后根据子问题的结果构造出原问题的答案。这里有点动态规划的意思,所以说运用分治算法也需要满足一些条件,你的原问题结果应该...原创 2021-05-14 14:40:49 · 102 阅读 · 0 评论 -
数组的前缀和及查分数组
1,前缀和主要适用场景是原始数组不会被修改的情况下,频繁查询某个区间的累加和。这里就不写前缀和的代码了,就是用一个数组记录下原有数组的前缀和。比如,prefix[i]就代表着nums[0…i-1]所有元素的累加和,如果我们想求区间nums[i…j]的累加和,只要计算prefix[j + 1] - prefix[i]即可,而不需要遍历整个区间求和。(需要注意的是使用场景是频繁查询某个区间的累加和,而不需要对原始数组进行频繁修改)2,查分数组的主要适用场景是**频繁对原始数组的某个区间的元素进行增减。**比原创 2021-05-13 23:55:38 · 716 阅读 · 0 评论 -
LeetCode 382 链表随机节点
分析随机算法中的水塘抽样算法。当遇到第i个元素时,应该有1/i的概率选择该元素,1 - 1/i的概率保持原有的选择。假设一共有n个元素,我们要的随机性无非就是每个元素被选择的概率都是1/n。对于第i个元素,它被选择的概率是:(1/i)(1 - 1/(i+1))(1 - 1/(i+2))…(1 - 1/n)这个式子化简以后就是1/n。代码int getRandom() { int ans = 0; ListNode* p = this -> head; .原创 2021-05-13 22:06:04 · 76 阅读 · 0 评论 -
LeetCode 645 错误的集合
分析这个题可以使用哈希表记录一下,这样时间空间复杂度都是O(N),要想实现空间复杂度是O(1)的算法,需要使用映射。暂且将nuns中的元素变为[0…N -1],这样每个元素就和一个数组索引对应了,有一个元素重复了,同时导致一个元素缺失会导致有两个元素对应到了同一个索引,而且会有一个索引没有元素对应过去。我们可以通过将每个索引对应的元素变成负数,以表示这个索引被对应过一次了。缺失的元素索引最后对应的数据是正的,这样就可以找到重复和缺失的元素了。代码class Solution {public: .原创 2021-05-13 17:16:05 · 124 阅读 · 0 评论 -
LeetCode 268 丢失的数字
分析位运算中异或运算,相同得0,不同得1,0与任何数A做异或运算的结果都是A,且异或运算满足交换律。这道题目可以假设先补齐一位,这样做以后可以发现除了缺少元素之外,所有的索引和元素都组成一队了,只要把所有的元素和索引做异或运算,成对儿的数字都会消失为0,最后剩下的元素即为丢失的元素。代码class Solution {public: int missingNumber(vector<int>& nums) { int ans = 0; ..原创 2021-05-12 22:01:25 · 69 阅读 · 0 评论 -
LeetCode 239 滑动窗口最大值
分析滑动窗口问题,本题设计了一个单调队列来保证取出窗口内最大值的时间复杂度是O(1)。代码class Solution {public: class myqueue{ //设计单调队列 deque<int> q; public: void push(int n){ while(!q.empty() && q.back() < n){ q.pop_bac.原创 2021-05-12 17:39:54 · 53 阅读 · 0 评论 -
滑动窗口问题 LeetCode 72 最小覆盖子串
滑动窗口一般用来解决子串问题,滑动窗口算法的代码框架如下:void slidingWindow(string s, string t){ unordered_map<char, int> need, window; //need中存放的是满足条件的字符及个数 for(char c : t) need[c]++; int left = 0, right = 0; //valid变量表示窗口中满足need条件的字符个数 int valid = 0; while(right <原创 2021-04-28 17:56:17 · 72 阅读 · 0 评论 -
LeetCode 503 下一个最大元素
分析这个题目是一个环形数组,我们先把问题简化一下,不考虑环形数组。解题思路使用单调栈(单调栈实际就是栈,只是利用了一些巧妙的逻辑,使得每次元素入栈后,栈内元素都保持有序)。class Solution {public: vector<int> nextGreaterElements(vector<int>& nums) { int n = nums.size(); vector<int> ans(n); .原创 2021-04-22 11:47:36 · 69 阅读 · 0 评论 -
LeetCode上面的nSum问题
1)twoSum返回nums中所有两个元素之和等于target的对,并且不能出现重复的。vector<vector<int>> twoSumTarget(vector<int>& nums, int target){ sort(nums.begin(), nums.end()); vector<vector<int>> res; int l = 0; int r = nums.size() - 1; while(l <原创 2021-04-21 22:49:39 · 218 阅读 · 0 评论 -
LeetCode 316 去除重复字母
分析这个题是去重相关算法中难度最大的,这道题搞懂,其他的就不在话下了。这道题目需要保证以下三点:1)要去重2)去重字符串中的字符顺序不能打乱s中字符出现的相对顺序3)在所有符合上面两条要求的所有字符串中,取字典序最小的作为最终结果先只考虑前两点,我们可以使用一个栈stk和一个数组inStack来辅助实现。栈中存放的是满足前两点的字符串。当是inStack[s[i]]在栈中就忽略这次处理,否则把s[i]入栈,更新inStack[s[i]]的值。然后考虑怎么来满足第三点,我们使用一个count数组.原创 2021-04-21 10:13:09 · 81 阅读 · 0 评论 -
用O(1)时间,查找/删除数组中的任意元素LeetCode 380
分析本题的难点在于两点:1)插入、删除,获取随机元素这三个操作的时间复杂度都是O(1)2)getRandom方法返回的元素必须等概率返回随机元素。如果想真正意思上用O(1)时间实现取元素,那么只能通过数组作为底层的实现结构,但是如果使用数组作为实现结构的话**,怎么实现删除的时间是O(1)呢,可以先把元素换到最后一个,然后在删除,**这样就可以达到目的了。交换两个元素必须通过索引实现,可以用一个hashtable来保存对应的索引。那么哈希表能不能实现O(1)时间getRandom呢?是不可以的,因.原创 2021-04-20 15:15:35 · 297 阅读 · 0 评论 -
LeetCode 875 爱吃香蕉的珂珂
分析这是一道二分查找的题目,通过题目的意思可以知道,keke吃香蕉的最小速度是1个/小时,最快速度是max(nums)每小时,只要从[1,max(nums)]满足条件的最小速度即可。这样的话程序的时间复杂度是O(NlogM),注意,M是数组nums中的最大的数代码class Solution {public: int minEatingSpeed(vector<int>& piles, int h) { int left = 1; in.原创 2021-04-20 10:30:39 · 121 阅读 · 0 评论 -
LeetCode 341 扁平化嵌套列表迭代器
分析这道题是一道设计题,思路参考了labuladong中写的文章,自己想不出来。值得复习。。。代码class NestedIterator {private: vector<int> it; int index; public: NestedIterator(vector<NestedInteger> &nestedList) { //将列表打平到vector中,可以把嵌套列表看成一颗N叉树 vector&l.原创 2021-04-19 23:01:29 · 98 阅读 · 0 评论 -
LeetCode 1 两数之和
分析暴力解法的时间复杂度是o(n*n),如果我们使用一个哈希表记录一下结果,时间复杂度会变成O(n),空间复杂度也会变成O(n)。两数之和的问题就是教我们使用哈希表处理问题。代码class Solution {public: vector<int> twoSum(vector<int>& nums, int target) { unordered_map<int, int> hash; int size = nu.原创 2021-04-19 20:31:22 · 53 阅读 · 0 评论 -
二分查找总结
1,最普通的二分查找,数组中没有重复元素二分查找的概念已经很熟悉了,这里直接上代码,需要注意的点都在代码中以注释的形式标注。int binarySearch(int[] nums, int target){ int left = 0; int right = nums.size() - 1; while(left <= right){//这里有没有=号,取决于是左闭右开还是左闭右闭 //这里求mid之所以不写成mid = (right + left)/2,是有可能会整数溢出,而代码中这原创 2021-04-19 14:28:25 · 69 阅读 · 0 评论 -
LeetCode 450 删除二叉搜索树中的节点
分析二叉搜索树的递归框架如下:TreeNode* BST(TreeNode* root, int target){ if(root != nullptr) return root; if(root -> val == target){ //找到目标,该做什么 }else if(root -> val < target){ root -> right = BST(root -> right, target); }else{ root -> lef.原创 2021-04-16 16:35:42 · 69 阅读 · 0 评论 -
LeetCode 538 把二叉树转换成累加树
分析BST相关的问题,不是利用BST做小右大的特性提升算法效率,就是利用中序遍历的特性满足题目要求。这道题目我们利用中序遍历,但是是按照右中左的顺序访问的,而且会在外部维护一个sum来记录遍历到当前结点的和。代码如下:代码class Solution {public: int sum;//记录和 TreeNode* convertBST(TreeNode* root) { sum = 0; traverse(root); retur.原创 2021-04-15 09:59:04 · 68 阅读 · 0 评论 -
LeetCode 652 寻找重复的子树
分析二叉树的题目需要判断使用前序中序还是后序,怎么判断呢?这就需要根据题意,思考一个二叉树结点需要做什么。比如这道题目,需要注意两点:1)以我为根的这棵二叉树(子树)长啥样2)以其他结点为根的子树长什么样子**根据树的序列化和反序列化,已经知道,如果唯一的确定一棵二叉树,这里我们使用后序遍历。**只需要将每棵二叉树的序列化后的s放入到一个map中即可(在放入之前,看一看有没有其他的树和要放入的树相同)。代码class Solution {public: map<string,.原创 2021-04-14 23:48:18 · 114 阅读 · 0 评论 -
LeetCode 297 二叉树的序列化和反序列化
分析需要注意的是,一般情况下,单单前序遍历是不能还原二叉树结构的,因为缺少空指针的信息,至少要得到前中后序遍历中的两种才能还原二叉树。但是我们可以记录空指针的位置,这样就可以唯一确定一棵二叉树。后序遍历也可以完成,但是需要注意的是,中序遍历是不可以的,因为反序列化要求先拿到root节点,中序遍历做不到这一点。这道题目除了前后序遍历可以解决,层次遍历也是可以解决的。这里不写代码了。代码//前序遍历代码class Codec {public: // Encodes a tree to a.原创 2021-04-14 16:40:27 · 87 阅读 · 0 评论 -
LeetCode 222 完全二叉树的节点个数
分析如果是一棵普通的二叉树,返回树中结点个数的代码如下:int countNodes(TreeNode* root){ if(null == root) return 0; return 1 + countNodes(root -> left) + countNodes(root -> right);}如果是一棵满二叉树,结点总数就和树的高度呈指数关系,时间复杂度是O(logN * logN)( 思考为什么):int countNodes(TreeNode* root){.原创 2021-04-13 13:19:35 · 84 阅读 · 0 评论