标签:核心 算法 自身 获取 代码实现 null fas 注意 rem
删除倒数第N个结点
解题思路
声明两个指针,快指针先移动n次,然后快慢指针同时移动,直到快指针为null。
此时慢指针指向了倒数第n个结点的前驱结点,然后删除慢指针后继结点即可。
需要注意的是当删除倒数第n(n与链表长度相同)时,快指针会直接移动到null。
此时需要单独处理,直接将head指向head的后继结点即可。
public ListNode RemoveNthFromEnd(ListNode head, int n) { ListNode zero=new ListNode(0); zero.next=head; ListNode fast=zero; ListNode slow=zero; //若链表只有一个结点,直接清空 if(head.next==null){ head=null; return head; }//将快指针放向前移动n次 for(int i=1;i<=n+1;i++) fast=fast.next; //如果快指针已经为空,说明清除的是第一个结点,直接将head指向其后继结点 if(fast==null){ head=head.next; return head; } //循环遍历链表直到快指针到达尾部 while(fast!=null){ fast=fast.next; slow=slow.next; } //此时slow的后继结点为要删除的倒数第n个结点 slow.next=slow.next.next; return zero.next; }
合并两个有序链表
解题思路
使用递归方法调用自身,让结点一直递归到两个链表中其中一个比另一个尾部的结点大的结点。
到最后一次调用自身,会触发两个if中的一个,返回链表剩余的结点。
每次返回链表的首节点都会成为上一个结点的后继结点,不断返回后,就实现了两个链表有序的合并。
public ListNode MergeTwoLists(ListNode l1, ListNode l2) { if(l1==null)return l2; if(l2==null)return l1; ListNode newList=null; //递归调用自身,递归到两链表中最后剩的最大的链表,赋值为前一个小值的next if(l1.val<=l2.val){ newList=l1; newList.next=MergeTwoLists(l1.next,l2); } else{ newList=l2; newList.next=MergeTwoLists(l1,l2.next); } return newList; }
检查链表中是否有环
解题思路
使用快慢指针,快指针一次步进慢指针的n倍,如果存在环,二者会不断循环,最终会有追上且二者相等的情况。
如果不存在环,快指针或快指针的后继结点肯定会等于null,返回false。
public bool HasCycle(ListNode head) { //快慢指针检测单链表中是否存在环 if(head==null||head.next==null)return false; //快指针一次前进n倍慢指针的步数 ListNode fastNode=head.next; ListNode slowNode=head; //如果存在环,二者一定会碰上,得到相等的情况 while(fastNode!=slowNode){ if(fastNode==null||fastNode.next==null)return false; fastNode=fastNode.next.next; slowNode=slowNode.next; } return true; }
反转链表
解题思路
反转链表的核心就是让等待被提到前面的结点标记为当前结点,让等待别的结点到自己前面的结点称为前驱结点,记录下当前结点的后继结点。
然后将当前结点提到前驱结点前,第一次循环时,链表会断开。然后更新当前结点、前驱结点。
之后的循环每次都是先记录下当前结点的后继结点作为下一次循环的当前结点,再执行提前和更新操作。
public ListNode ReverseList(ListNode head) { if(head==null)return head; ListNode pre=head; ListNode cur=head.next; ListNode temp; while (cur!= null) { //第一次循环时将第二个结点提到第一个节点前,此时链表断开。 //之后的循环就是不断将后部分的首结点提到前部分的首位。 //同时更新pre、cur和temp指针为前部分的首结点、后部分的首结点和后部分首结点的后继结点。 temp=cur.next;//设置后继结点指针 cur.next=pre;//将当前结点提到前驱结点前 pre=cur;//设置前驱结点指针 cur=temp;//设置当前结点指针 } head.next=null; return pre; }
获取链表的中间结点
解题思路
获取其中间结点我也是使用了快慢指针,让快慢指针都以后继结点为head出发。
快指针步进为慢指针的二倍,快指针或快指针的后继结点为null就返回慢指针,慢指针即为中间结点。
public ListNode MiddleNode(ListNode head) { ListNode zero = new ListNode(0); zero = head; //快指针和慢指针以head为next开始 ListNode fast = zero; ListNode slow = zero; if (head.next == null) return head; while (true) { //快慢指针步进 fast = fast.next.next; slow = slow.next; //直到快指针为null或快指针的后继结点为null,返回慢指针指向的结点 if (fast == null||fast.next == null) return slow; } }
标签:核心 算法 自身 获取 代码实现 null fas 注意 rem
原文地址:https://www.cnblogs.com/errornull/p/9860724.html