方便于增加删除,不方便于找元素
每个node有两个属性,一个data值,一个next node
做任何事之前,先把可能越界的情况的判断先写出来,比如必须得是大于0的情况若一开始就<0 则直接return什么,或者一上来就为空的话则直接return什么
做任何链表题,先判断若链表为空或者链表只有一个node时应怎么处理;有时也要考虑因为单链表只能access到next,若要对第一个node进行操作,如果定位到head并能对其操作是个值得思考的点
Java中没有直接得到链表长度的内置method,所以要自己用while去遍历得到链表长度
一般return一个链表的话就是return这个链表的头部结点即可
一般在链表题中,不亲自用head去遍历,而是一开始用一个等于head的node比如cur去遍历,因为如果一直在动head的话会改变原链表的结构。如果后面还需要用到原链表的的话就找不到了(比如要返回链表的时候得返回头节点,就得用到head)
新建链表时/要从链表第一个node开始改变时 一个降低错误率的小技巧:设置一个预先指针pre,pre.next才是真正的head,返回结果链表时也是返回pre.next。在连接起新链表时,先让一个新node cur去等于pre,之后的涉及到设置下一位来建立起链表的操作都让cur去进行。这样做的好处时最后返回头节点时不会因为建立新连接的操作而丢失头节点。与上面那个方法的区别在于,因为这里不知道头节点的值应为多少或是因为要从第一个node就开始改变,所以如何去为头节点搭建一个创造环境就是难点,这里用了pre来解决
链表中node1==node2 与node1.val==node2.val是不同的,前者表示必须是同一node,后者只要值相等就行
找链表中点时,要确定当链表长度为偶数时,中点是取靠前的还是靠后的那个,这两个在写法上有细微差别,但若搞错会造成代码不work
指针常用于去解决链表问题,且时间复杂度一般为O(1)
遍历链表的循环条件一般为while(...==null或...!=null或....next==null等等,可以加多个next,也可以通过&& 或||组合起来使用),但在写循环结束条件时要注意的就是null pointer exception,所以要仔细检查循环结束条件的设置是否合理,是否会漏掉某些情况造成后面逻辑错误,会不会产生null pointer等等
一般对链表问题用递归时,call自己这个function时括号里的参数是(cur.next)
一些next或pre关系比较复杂或容易混淆的话,可以通过画图理清
双链表的好处:有pre这个属性,可以方便access到某node的前一个node;但在双链表的增加删除操作中也要记得不仅要维护next属性也要维护pre属性
一些常见的对链表的基本操作,一些复杂的题可能是由这些基本操作拼接起来的:
- 删除链表中某个node(且只能访问该node)(面试题02.03)
- 找链表中点(当链表为偶数链表时,需要确定中点是取靠前的node还是靠后的node)
- 返回倒数第k个node
- 反转链表(用迭代比较好)
- 快慢指针