链表篇(下 代码随想录二刷+总结)
1.删除链表的倒数第N个结点
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode first = head;
ListNode second = head;
ListNode virtue = new ListNode(-1,head);
for(int i=0;i<n;i++){
second = second.next;
}
ListNode pre = virtue;
while(second!=null){
second = second.next;
pre = first;
first = first.next;
}
pre.next = first.next;
return virtue.next;
}
}
双指针法:设置first指针指向起始位置,second位置指向顺序第n个位置,然后同时遍历,当second指向空时,first自然指向倒数第n个位置了,这里设置虚拟节点是为了保持一致操作,不设置虚拟节点遇到了head=[1],n=1时就会出错。
针对链表问题,虚拟节点的设置到底影不影响代码,这个要具体分析,个人建议统一设置虚拟节点,出错几率小。
2.链表相交
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
int lengthA=0;
int lengthB=0;
ListNode temA = headA;
ListNode temB = headB;
while(temA!=null){
temA = temA.next;
lengthA++;
}
while(temB!=null){
temB = temB.next;
lengthB++;
}
if(lengthA<lengthB){
return getNode(headB,headA,lengthB,lengthA);
}else{
return getNode(headA,headB,lengthA,lengthB);
}
}
public ListNode getNode(ListNode Long,ListNode shor,int len_long,int len_short){
for(int i=0;i<(len_long-len_short);i++){
Long = Long.next;
}
while(Long!=null){
//equals方法默认比较两个对象引用的地址
if(Long.equals(shor)){
return Long;
}
Long = Long.next;
shor = shor.next;
}
return null;
}
}
要找相交的点,则一定要以短链表头为起始位置开始找,所以第一步要先将长链表的位置前移到至节点剩余和短链表结点个数一致。然后去遍历比较找到有没有相同结点即可。
3.环形链表Ⅱ
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while(fast!=null&&fast.next!=null){
slow = slow.next;
fast = fast.next.next;
if(slow==fast){
ListNode index1 = slow;
ListNode index2 = head;
while(index1!=index2){
index1 = index1.next;
index2 = index2.next;
}
return index1;
}
}
return null;
}
找环形链表的入环节点,首先要确认这个链表是不是一个环。针对这个问题,设置快慢指针,初始皆指向head,在遍历过程中,fast指针一次跳两个结点,slow跳一个,当slow和fast可以相遇则说明这个链表是个环,循环条件设置fast和fast.next(fast满足slow当然满足,反之不然)。找到环之后要找第一个入环节点,从head处和slow和fast相遇处各自以一个step跳动,相遇处即为入环处。详细推导如下
哈希表法
public class Solution {
public ListNode detectCycle(ListNode head) {
HashSet<ListNode>hs = new HashSet<>();
ListNode temp = head;
while(temp!=null){
if(hs.contains(temp)){
return temp;
}
hs.add(temp);
temp = temp.next;
}
return null;
}
}
思路简单,费时费力。将遇到的node存入hashset中,若再次遇到则证明其有环,且当前节点为第一个入环节点,直接return。