
算法
文章平均质量分 82
算法
-代号9527
逢山开路,遇水搭桥!纸上得来终觉浅,绝知此事要躬行。
展开
-
【Leetcode】二十二、两数之和、两数相加、合并有序链表、两两交换链表节点
说白了就是两个数的加法,不过这两个数,存在链表里,且是个位数在最左边,如[2,4,3]就是数字342,这样倒着存,相加的时候,直接按顺序遍历链表,即是先按个十百千万的顺序算。如上图,绿色方框为一次递归,蓝色方框是第二层递归,第二层递归,交换后,返回4,退到第一层递归,让head.next指向第二层递归的返回值,即1指向4,完成全部交换。不玩指针指向,链表转数组,i和i+1交换值,然后数组转回链表,就解决了,但没必要这样,练习下链表。比如1、2、3、4四个点,1、2一组,两两交换,3、4一组,两两交换,原创 2024-08-01 14:09:05 · 711 阅读 · 0 评论 -
【Leetcode】二十一、前缀树 + 词典中最长的单词
从优化后的代码可以看到,搜索和判断前缀的区别是,判断到输入字符的最后一个字母后,搜索要有isEnd标志为true,表示有这样的单词,以免出现,搜abc,但只有abcd时也返回true的情况。比如app单词,a字母找到了,且isEnd为true,往下ap,也找到了,且isEnd为true,如此app这个单词就是目前符合要求的。此外,正常来说,每个Trie节点的值val也要存一下,但对英文字母不用,因为其对应的SSCII码,可以当下标,下标转一下就是字母值。root节点,一般不存数据,其下有孩子节点。原创 2024-07-16 15:48:00 · 1057 阅读 · 0 评论 -
【Leetcode】二十、记忆化搜索:零钱兑换
动态规划,重在状态转移,那些不用的中间值,存不存在你。amount = 14的剩余金额中,剩余7时,最优解最小,为1,因此14最优解就是 1 + 1 = 2。然后将F(0)存在数组下标为0的地方,F(3)存数组下标为3的地方,计算一个值时,先在数组中找,找不到时再计算。可以发现,计算左侧一支的F(4)时,会得到F(3)的值,存下F(3)的值的话,执行到右侧一支计算F(3)时,直接取就行。因此,amount的最优解是2。也叫备忘录,即把已经计算过的结果存下来,下次再遇到,就直接取,不用重新计算。原创 2024-07-27 16:06:58 · 611 阅读 · 0 评论 -
【Leetcode】十九、贪心算法:玩筹码 + 跳跃游戏
第 i 个筹码在 position[i],position = [2,2,2,3,3],就是说,第一个筹码在2号位置,第二个筹码也在2号位置,第三个筹码也在2号位置。往下遍历,一旦出现最远可达到的位置reachRight > 终点下标,即终止循环,返回true,反之,遍历完也不满足 reachRight > 终点下标,则返回false。再看上面这个例子,连续取两个5分后,差1,但现在没有1分的面值。但其实,这样也有坑,比如上面这样,按照贪心,结果是10 + 2 + 2,但最优解是 7 + 7。原创 2024-07-27 15:05:05 · 631 阅读 · 0 评论 -
【Leetcode】十八、动态规划:不同路径 + 全1的最大正方形
因为只能向下、向右走,所以从起始点走到点(R,C),路径数等于,以起始点到点(R,C)为对角线的矩形里,到点(R,C)左侧点的路径数 + 到点(R,C)上边点的路径数。从起始状态(0,0),到终止状态(R,C),中间每个格子的值(到达它的路径数),都会算出来,这些中间结果,可存入一个数组,这题可用二维数组存。前面已经分析过了,这儿的方程式为:F(m,n)= F(m - 1,n)+ F(m,n - 1),初始状态为(1,1),终止状态为(m,n)只能向下、向右的走,从图中左上角走到右下角,有几条路径。原创 2024-07-23 21:19:16 · 1162 阅读 · 1 评论 -
【LeetCode】十七、并查集:岛屿数量
有个数组array,长度为10,若array[1] = 6,说明1号元素的上级是6号元素。两个集合合并,或者说两个门派合并,看似改动很大,其实只要让一个门派的教主给另一个门派的教主当上级即可。想实现这个效果,可以:查询到x元素的根节点(教主)后,直接将x元素的上级改成根节点。合并后,比如让第一个集合的教主做合并后新集合的教主:5号的上级不再是自己,变成了1。也就是说,第一次find元素x,是没有压缩路径的,第二次才是优化后的效果。对应的数组:数组索引代表元素,数组的值,代表这个位置的元素的上级。原创 2024-07-15 10:43:37 · 745 阅读 · 0 评论 -
【Leetcode】十六、深度优先搜索 & 宽度优先搜索 :二叉树的层序遍历
从root开始,root入队,count = 1,出队,同时root的左、右节点入队,并维护count。从root开始,一条路往下走,和前面一层层的取不一样了,DFS解时,每层递归有个level,level = 0,即root节点所在的那层,放到结果集result的0号位置,往下9,放到result的1号元素里面。先逮着1开始走,1符号要求,放入结果集,接着往下走,[1,2],也符合要求,放入结果集,接着往下走,[1,2,3],也符合要求,放入结果集,再往下,就到底了。和上面分析的BFS遍历二叉树不一样,原创 2024-07-17 20:35:19 · 1345 阅读 · 0 评论 -
【LeetCode】十五、回溯法:括号生成 + 子集
如此,枚举所有可能性的过程中,如果出现左括号的数量 < 右括号的数量,则说明此路不通,终止递归,回溯到上一步重新选择。以上注意:遍历前面的结果集里的每个元素时,用一个copy对象,防止引用传递。以空集开始,遍历给定集合的每个元素,并把上面每一层的结果和当前元素相加。比如给定[1,2,3]就得到了第四层:[3] 、[1,3]、 [2,3] 、[1,2,3]。原创 2024-07-16 16:25:22 · 514 阅读 · 0 评论 -
【LeetCode】十四、分治法:多数元素 + 最大子序列和
这里用分治法解决一下:把一组数分成一个个不可再分的元素(分治法里所说的小问题),再分别求众数,往上开始一层回退递归,如果左边有一半以上的数是n,右边也有一半以上的数是n,那左右两边合并后,多数元素就也是n。其次,每次左右两边的众数如果相等,则这一个区间的众数就是该值,反之,左右两边的众数值不一样,那就要比较这两个众数在区间里出现的次数,来决定选谁,如果连出现的次数也一样,那就随机取一个。因此说:左右两边分别是有序的,那把它两合并成一个新的有序的结果是更容易的。组合小问题的解,就是最终的排序结果。原创 2024-07-04 17:53:44 · 794 阅读 · 0 评论 -
【LeetCode】十三、递归:斐波那契 + 反转链表
以hello为例,第一层递归,L = 0,R = 4,进入第二层递归,L = 1,R = 3,进入第三层递归,L= 2,R = 2,此时,触底,第三层递归函数执行return,结束,出栈。如上,第一层递归,L = 0,R = 4,但其传入下一层递归的L和R分别为1和3。这里以双指针的思想为基础,硬套一层递归来实现:还是L和r两个指针,递归终止的条件是 L >= r,递归的拆解则是每次L指针+1,r指针-1,递归要传递的参数不再是一个,而是L和 r 两个,上一层递归结束,回溯回来时,交换L和r位置的元素。原创 2024-07-03 20:55:22 · 1122 阅读 · 0 评论 -
【LeetCode】十二、滑动窗口:长度最小的子数组 + 定长子串的元音最大数目
依旧每次让i++前进一位,但结果不再重新累加,而是下一组的和 = 上一组的和 - 上一组的第一个元素 + 新框进来的元素。像窗口向前滑动,每次和上次相比,多了一个新元素,少了最开始的一个旧元素。,接着再继续去掉array的第一个元素,直到不满足 >=s的条件时,窗口向前滑动,直到出现第二个子数组array。定长,考虑滑动窗口,先计算第一个k长度的窗口的元音数量,然后一步一步滑动到末尾,期间取Math.max()这题两个关键点:一是要求子数组是连续的,二是子数组不是定长的,但也可以用滑动窗口。原创 2024-07-03 16:12:43 · 680 阅读 · 0 评论 -
【LeetCode】十一、二分查找法:寻找峰值 + 二维矩阵的搜索
第一个想法是:先普通的二分查找value,返回-1后,说明不存在,那就再遍历这个数组,用双指针,当p1的值 < value && p2的值 > value时,return p1 + 1,但这样应该是复杂了。,如果有等于target的,那返回其下标,如果不存在,那就要插入到第一个比target大的值的位置,第一个大的值的下标则往后移动一位。在有序的集合里找一个数字,可以二分查找。找一个数,有序的情况下,直接遍历找,时间复杂度为O(n),用二分法,一半一半的砍着找,则时间复杂度为O(log n),更优。原创 2024-07-02 20:58:24 · 960 阅读 · 0 评论 -
【LeetCode】十、双指针算法:环形链表检测 + 救生艇
最先想到的是,两层循环,遍历array,如外层 i = 1,内层循环 j = 4 5 7 9,外层 i = 4,内层循环 j = 1 5 7 9……其实本质是两个人的体重之和问题,和上面提到的对撞指针很像,不过一个是等号,一个是小于号,因此考虑先给所有人的体重从小到大排个序(因为排序是对撞指针移动的基础前提)此时可用快慢双指针,慢的一次走一步,s = s.next,快的一次走两步,f = f.next.next,二者同时从队首出发:。移动三次后,快慢指针相遇了,这说明是个环形,否则二者不会相遇。原创 2024-06-28 15:06:33 · 540 阅读 · 0 评论 -
【LeetCode】九、堆的使用:第K个最大元素 + 前K和高频单词
可用HashMap,统计完后,前k个、第K个,则可考虑最大堆。不过,题中要求次数相等时,按照字母排序,因此,要自定义比较器的实现:先比次数,次数相等再按字母排序。如果要用最小堆实现:应该将值最小的元素往堆顶放、同等次数的把字母靠后的往堆顶放。这题应该快排来解,这里用堆仅做练习。原创 2024-06-27 19:50:16 · 432 阅读 · 0 评论 -
【LeetCode】八、树、堆、图
如下,一个数组转为一个完全二叉树,其结果是唯一的(遍历数组,从上到下、从左到右的摆放),即0号元素当根节点,后面两个1、2号元素当根节点的左右子节点,3、4、5、6号元素分别当1、2号元素所在节点的左右子节点。如下:整个树看成三块,A、A的左子树、A的右子树,在两块子树里,继续按中序的左根右遍历,结果就是:D ⇒ B ⇒ E ⇒ A ⇒ F ⇒ C ⇒ G。同理,换完后,第二层不再满足最小堆,需要再交换,10 > 8 也有 10 > 7,选最小的7这个节点进行交换。堆化,即把一组无序的数加到堆里去。原创 2024-06-27 19:49:02 · 810 阅读 · 0 评论 -
【LeetCode】七、哈希集合Set相关:存在重复元素判断 + MyHashSet设计
思路:重复的判断,借助数据结构的set,数组的长度 > set集合的长度,即有重复。相比之前对这个题的解法,很明显的感觉到,用上数据结构,比无脑for循环要快很多。,删除一个10,就把下标索引为10的地方改为false,重复放进来同一个值,仍然为true,符合Set集合的不重复。主要作用:查看是否有重复元素(给一个数组,转为set,数组的长度 > set的长度,即有重复元素)实现自己的HashSet类,那也就要达到搜索、插入、删除的时间复杂度为O(1),原创 2024-06-27 19:48:06 · 392 阅读 · 0 评论 -
【LeetCode】六、哈希表相关:统计重复元素 + 找不同
又叫散列表,存键值对,将key用哈希函数转为数组下标索引当两个不同的key经过哈希函数得到相同的结果i,即哈希冲突了此时 i 位置就要存两个值,因此,链表出现,如下图中数组下标2的位置:时间复杂度:根据key找value,时间复杂度为O(1),但如果有哈希冲突,则时间复杂度为O(k),k为冲突位置链表元素的个数下面这种用数组表示哈希表的结构,是key为下标索引,value为数组元素的值。重点关注HashMap就行:单论这题要return的结果,其实不借助数据结构,直接for循环遍历,里面再嵌套遍历原创 2024-06-27 13:40:05 · 865 阅读 · 0 评论 -
【LeetCode】五、栈相关:有效的括号 + 下一个更大的元素
期间如果中途取到了更大的值,则存一下,以防有多个更大的值,下次出现更大的值,不论大小,直接覆盖,因为取的是下一个更大元素,不是下一个更大的元素里的最大的元素。每循环一次,处理num1的一个元素,num2的栈元素也会被弹出,等处理num1的下一个元素时,num2的栈就不完整了,因此,这里用一个tmp临时栈,记录num2栈被弹出的元素,后面再塞回num2栈,以便处理num1的下一个元素。有没有比该元素大的,如果采用栈,将num2入栈,遍历num1的每个元素n,每次弹出栈顶元素来比较,根据这个特点:比较的是。原创 2024-06-27 13:38:04 · 530 阅读 · 0 评论 -
【LeetCode】四、队列相关:最近的请求次数
比如下面,1ms、100ms的时候分别进来两个请求,此时返回2,3001的时候再进来一个请求,[3001-3000,3001]的请求数量为3,3002的时候再进来一个请求,[3002-3000,3002]区间,1ms的请求就不算了,返回3。思路:用一个队列,每进来一个请求(或者说每入队一个时间t),就对比最先入队的元素,判断其是否出t-3000和t闭区间,是则不再题目的统计范围,移除。很逆天的题目描述,就是不同时间会有请求发来,现在需要计算t-3000和t闭区间之内的请求次数。原创 2024-06-26 14:34:16 · 378 阅读 · 0 评论 -
【LeetCode】三、链表相关:移除与反转链表
此外,要求最后返回新的头节点,只靠一直往下移动的pre和head,遍历完后,无法获得头节点信息(单向链表),因此还要加一个虚拟节点dummy(位置在传入的head的前一个节点),dummy的next等于传入的头节点,dummy的val则随便给,反正用不到。满足则让当前节点head的前一个节点指向head.next,完成删除,但当前为单向链表,获取不到前一个节点,因此需要维护一个pre node的值,记录遍历到的当前节点的head的前一个节点,以便进行删除操作。原创 2024-06-26 14:34:00 · 725 阅读 · 0 评论 -
【LeetCode】二、数组相关:双指针算法 + 置换
当左指针L >= 右指针R时,说明已经全部遍历了一遍了,此时,看下,如果L所在的值为val,说明其前面全都是不等于val的值,比如L为4,说明当前位置下标为4,前面为0、1、2、3这四个元素,返回的数量就是4,也即L的值,反之,L所在的值不等于val,说明当前位置的值及其前面的值,都是不等于val的值,数量 = 索引 + 1,返回L + 1。一开始想的是:遍历找为0的元素,找到一个就将其后面的所有元素往前移动一位,然后将这个为0的元素自身扔在数组末尾。访问时,时间复杂度为O(1)原创 2024-06-25 19:58:39 · 1247 阅读 · 0 评论 -
【Leetcode】一、排序
插入排序,正如这个名字,就像打牌一样,整牌时,比如现在最大的放在左边,那抽到一张新牌后,从右往左看,一个个比较,然后把新进来的牌插入到合适的位置。到这儿,想到一点,算法,即解决问题的步骤,把生活中怎么解决同样问题的行为,翻译成代码,就是答案。此外,解一道题,应该先举一个简单具体的例子,分析清楚后,再逐步扩大数据量来分析。前面选择排序是,我找到最值后,手动给它放到数组首位。冒泡则是:第n个元素和第n+1个元素对比,交换,让大的那个放右边,接着n+1和n+2位置的元素对比,依旧大的放右边。原创 2024-07-19 20:25:18 · 613 阅读 · 0 评论