算法
文章平均质量分 92
鹏鹏程序员
这个作者很懒,什么都没留下…
展开
-
6.1 理解树的结构
注意:本关讲义我们主要看原理,不写可执行代码,因此我们只用伪码,不提供各种语言的定义。int val;这里本质上就是有两个引用,分别指向两个位置,为了便于理解,我们分别命名为左孩子和右孩子。如果是N叉树该如何定义呢?int val;那能否使用数组来存储二叉树呢?其实就是用数组来存储二叉树,顺序存储的方式如图:用数组来存储二叉树如何遍历的呢?如果父节点的数组下标是i,那么它的左孩子就是i*2+1,右孩子时i*2+2。但是用链式表示的二叉树,更有利于我们理解,所以一般我们都是用链式存储二叉树。原创 2023-11-22 10:35:43 · 111 阅读 · 0 评论 -
5.2 队栈和Hash的经典算法题
这个真不多,不过假如告诉你原始数组是有序的,那可以进一步优化,仍然采用两层循环的方式,外层任然是一个遍历,而内层循环可以换成二分,这样复杂度就从O(n^2)降到O(nlogn)。两个栈将底部拼接到一起就能实现队列的效果,通过队列也能实现栈的功能。,但是这样的问题是无法消除重复结果,例如如果输入[-1,0,1,2,-1,-4],返回的结果是[[-1,1,0],[-1,-1,2],[0,1,-1],[0,-1,1],[1,-1,0],[2,-1,-1]],如果我们再增加一个去重方法,将直接导致执行超时。原创 2023-09-15 09:30:38 · 224 阅读 · 0 评论 -
5.1 队列和Hash的特征
HashMap的实现原理是先要找到要存放数组的下标,如果是空的就存进去,如果不是空的就判断key值是否一样,如果一样就替换,如果不一样就以链表的形式存在链表中(从JDK8开始,根据元素数量选择使用链表还是红黑树存储)。8本来应该存到索引为1的位置,但是已经满了,所以继续向后找,索引3的位置是空的,所以8存到3位置。在上面的例子中,我们发现有些Hash中很多位置可能要存两个甚至多个元素,很明显单纯的数组是不行的,这种两个不同的输入值,根据同一散列函数计算出的散列值相同的现象叫做碰撞。接下来,我们看看如何取。原创 2023-09-14 14:58:29 · 259 阅读 · 0 评论 -
4.2 栈的经典算法问题
例如,如果当前第一个栈中的元素为 [2, 1, 5, 3, 9],那么第二个栈中的元素为 [2, 2, 5, 5, 9]。对于栈来说,如果一个元素 a 在入栈时,栈里有其它的元素 b, c, d,那么无论这个栈在之后经历了什么操作,只要 a 在栈中,b, c, d 就一定在栈中,因为在 a 被弹出之前,b, c, d 不会被弹出。首先看题目要求,给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s,判断字符串是否有效。// [5, 1, 5] - 5 既是栈顶元素,也是最大元素。原创 2023-08-07 16:32:23 · 171 阅读 · 0 评论 -
4.1 理解栈手写栈
栈底层实现仍然是链表或顺序表,栈与线性表最大的区别是数据的存取的操作被限制了,其插入和删除操作只允许在线性表的一端进行。一般而言,把允许操作的一端称为栈顶(Top),不可操作的一端称为栈底(Bottom),同时把插入元素的操作称为入栈(Push),删除元素的操作称为出栈(Pop)。再看具体内容之前,先补充一点,top有的地方指向栈顶元素,有的地方指向栈顶再往上一个空单位,这个根据题目要求设计就好,如果是面试的时候直接问面试官,top指向到哪里,本文采用指向栈顶空位置。14种可能,10种不可能,如上所示。原创 2023-08-07 11:38:38 · 74 阅读 · 0 评论 -
3.2 双指针思想以及应用
slow表示当前位置之前的元素都是不重复的,而fast则一直向后找,直到找到与slow位置不一样的,找到之后就将slow向后移动一个位置,并将arr[fast]复制给arr[slow],之后fast继续向后找,循环执行。要求:不需要额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。对于第二种情况,我们首先想到的是从头到尾遍历整个字符串,遇到空格的时候就将其后面的元素向后移动2个位置,但是这样的问题在前面说过会导致后面的元素大量移动,时间复杂度为O(n^2),执行的时候非常容易超时。原创 2023-08-07 09:42:57 · 218 阅读 · 0 评论 -
3.1 数组基础
而在 Java 里,默认会初始化为 0,而 Python 更为灵活可以直接指定是什么,例如 a=[1,2,3,4],就是数组里有4个元素,而 a=[0 for i in range(10)] 这样定义的数组就是 [0,0,0,0,0,0,0,0,0,0]初始化的本质就是覆盖已有的值,用你需要的值覆盖原来的 0,因为数组本来是 [0,0,0,0,0,0,0,0,0,0],这里只不过被你替换成了 [1,2,3,4,5,0,0,0,0,0]。其次,数组中的元素在内存中是连续存储的,且每个元素占用相同大小的内存。原创 2023-08-01 16:50:32 · 314 阅读 · 0 评论 -
2.2 链表反转扩展问题
很遗憾,这样是不行的,会将我们每个位置都加1,例如,如果原始单链表是 {7,8} 这里就会将其变成 {8,9},而不是我们要的 {7,9},导致这样的原因是循环处理链表每个结点元素的时候 sum=digit+1+carry 这一行会将每个位置都多加了一个 1,所以我们要使用变量 adder,只有第一次是加了1,之后该变量变成0了,就不会影响我们后继运算。在上一关介绍链表回文串的时候,我们介绍的是基于栈的,相对来说比较好理解,但是除此之外还有可以使用链表反转来进行,而且可以只反转一半链表,这种方式节省空间。原创 2023-08-01 09:37:21 · 182 阅读 · 1 评论 -
2.1 链表反转
给你单链表的头结点 head,请你反转链表,并返回反转后的链表。示例1:输入:head = [1,2,3,4,5]输出:[5,4,3,2,1]本题有两种方法,带头结点和不带头结点,我们都应该会,因为这两种方式都很重要,如果搞清楚,很多链表的算法题就不用做了。原创 2023-07-26 20:38:49 · 179 阅读 · 1 评论 -
1.2 链表高频面试题
假设公共子节点一定存在,第一轮遍历,假设La的长度为L1,Lb的长度为L2,则 |L2-L1| 就是两个的差值。这里需要用到两个栈,分别将两个链表的结点入两个栈,然后分别出栈,如果相等就继续出栈,一直找到最晚出栈的那一组。上面三种方法,第一种方法比较常规,第二种方法需要开辟一个O(n)的空间,还要考虑栈与链表的操作等,不中看也不中用。先看一个简单的问题:给你一个链表的头结点 head 和一个整数 val,请你删除链表中所有满足 Node.val == val 的结点,并返回新的头结点。原创 2023-07-22 10:13:43 · 458 阅读 · 1 评论 -
1.1 链表基础
删除的过程不算复杂,也是要找到删除结点的前驱结点,这里同样要在提前一个位置判断,例如下图中要删除5,其前驱结点是4。遍历的时候需要判断 cur.next 是否为5,如果是,则只要执行cur.next=null即可,此时结点5变得不可达,最终会被JVM回收掉。原创 2023-07-21 20:55:41 · 102 阅读 · 1 评论