力扣链表刷题总结(简单)
链表:链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
对于链表相关的题通常可以通过迭代、转换为数组、单指针、快慢指针等方法去做。通常为了节省时间或空间复杂度,会优先考虑快慢指针进行解题,置于其他时候具体问题需要具体分析。
关于链表的一些小技巧:
- 当需要产生一个新链表时,不妨设置含有虚拟节点的链表来存储新链表,可避免出现空指针异常
- 当需要删除某个节点的时,不妨定位到待删除节点的上一个节点,next 指针,使其指向待删除节点的下一个节点,即可完成删除操作
- 当需要找到第K个节点时,不妨考虑快慢指针,快指针走K步,慢指针走N-k步,当快指针为空时,慢指针的位置即为我们所求
- 当需要寻找某个位置时,不妨快慢指针多走几遍,相当于第一遍确定位置,第二遍寻值
注:对于其他问题,要具体问题具体分析,不是所有链表问题都适合采用以上技巧。刷算法题时,要多动脑子,不能形成思维定式,从题目中,一点点抽取关键问题。
吾日三省吾身:
- 付出不亚于任何人的努力
- 自立,自省,自爱,自强
- 谦虚低调,不卑不亢,常怀感恩之心
以下列举综合性较强的题解:
//合并两个升序链表 /** *思路:链表相关的问题多可用快慢指针的解法,设置两个指针分别指向两个链表,依次比较大小 *本题亮点:当产生一个新链表时,就创建一个dummy【虚拟头结点】,可避免出现空指针异常。 */ class Solution { public ListNode mergeTwoLists(ListNode list1, ListNode list2) { //首先建立一个新的链表,用于存储合并后的链表 ListNode dummy = new ListNode(-1); //此处空间置为-1就是为了占位 ListNode p = dummy; //将list两个链表分别存储在p1,p2中 ListNode p1 = list1,p2 = list2; //当两个链表均不为0时,方可以进行排序 while(p1 != null && p2 != null){ if(p1.val> p2.val){ p.next = p2; p2 = p2.next; }else{ p.next = p1; p1 = p1.next; } p = p.next; } //当两个链表分别为空时,则直接返回另一个链表即可 if(p1 == null){ p.next = p2; } if(p2==null){ p.next = p1; } return dummy.next; } }
//删除链表的第N个节点 /** *思路:因为删除后会产生一个新链表,所以直接定义含一个虚拟节点的新链表。 * 要删除第N个节点,只需要让(N-1)的下一个指针指向下一个地址即可 * 因为定义了虚拟节点,所以此处为n.next = n.next.next; * 亮点:本题需要先找到倒数第N个节点。 再使用 n.next = n.next.next; */ class Solution { public ListNode removeNthFromEnd(ListNode head, int n) { //定义虚拟节点链表 ListNode dummy = new ListNode(-1); dummy.next = head; //删除倒数第N个,要先找到倒数第N-1个 ListNode x = Findfrom(dummy,n+1); x.next = x.next.next; return dummy.next; } //此处参考找链表中倒数第N个节点 //先去找第N个节点 public ListNode Findfrom(ListNode head,int k){ //先定义一个指针 ListNode p1 =head; //先遍历一次链表,找出N的位置 for(int i= 0 ; i < k; i++){ p1 = p1.next; } //再定义一个指针,此时p1 和 p2正好相差了N-K 步 ListNode p2 = head; //当p1为空,即指向链表的末尾是,p2的位置就是所需节点的位置 while(p1 != null){ p2 = p2.next; p1 = p1.next; } return p2; } }
//环形链表 /** * 思路:判断链表中是否含环,通常采用的是快慢指针的做法。 * 重点:先判定链表为空否,再判断快慢指针相等否 */ public class Solution { public boolean hasCycle(ListNode head) { //首先定义快慢指针 ListNode fast = head,slow =head; //判断给定链表是否为空链表,若为空,直接返回false if (head == null || head.next == null){ return false; } //若链表不为空,则判断快指针是否为空 while(fast != null && fast.next != null){ //不为空,则慢指针走一步,快指针走两步 slow = slow.next; fast = fast.next.next; //当二者相等时,则代表存在环路 if(slow == fast){ return true; } } return false; } }
//相交链表 /** * 思路:根据题目可以得出如果两个链表相交,那么相交点之后的长度是相同的 * 同样建立两个指针,分别指向两个链表,并且从头结点位置开始,消除两个链表的长度差 即可 * 让两个链表从同距离末尾同等距离的位置开始遍历。这个位置只能是较短链表的头结点位置。 */ public class Solution { public ListNode getIntersectionNode(ListNode headA, ListNode headB) { //如果链表为空则无相交节点 if (headA == null || headB == null) return null; //建立两个指向链表头指针的节点 ListNode pA = headA, pB = headB; //等指针A.B不相等时,则证明无相交节点,继续遍历 while (pA != pB) { pA = pA == null ? headB : pA.next; pB = pB == null ? headA : pB.next; } return pA; } }