代码随想录算法训练营第四天| 24.两两交换链表中的节点、19.删除链表的倒数第N个节点、面试题02.07. 链表相交、142.环形链表II

24.两两交换链表中的节点

虚拟头结点法:

public class Solution {
    public ListNode SwapPairs(ListNode head) {
        ListNode dummyHead=new ListNode(0,head);
        ListNode cur=dummyHead;
        ListNode tmp=null;
        if(cur.next==null||cur.next.next==null)
        {
            return dummyHead.next;
        }
        while(cur.next!=null&&cur.next.next!=null)
        {
            ListNode t1=cur.next;
            ListNode t2=cur.next.next.next;
            cur.next=cur.next.next;
            cur.next.next=t1;
            cur.next.next.next=t2;
            cur=cur.next.next;
        }
        return dummyHead.next;
    }
}

注意要讨论头结点是否为空和只有头结点的情况,直接返回虚拟头结点的后一个,不用交换。后续的节点操作:先记录Cur指针的后一个节点T1以及Cur后面第三个节点T2,交换过后,Cur的后一个则变成Cur的后面第二个,Cur后一个的后一个则变成之前记录的T1,Cur的后面第三个仍为T2,此时Cur来到Cur后面第二个元素上,直到跳出循环,最终按题目要求返回该链表。

19.删除链表的倒数第N个节点

快慢指针法:

public class Solution {
    public ListNode RemoveNthFromEnd(ListNode head, int n) {
        ListNode dummyHead=new ListNode(0,head);
        ListNode fast=dummyHead;
        ListNode slow=dummyHead;
        while(n--!=0&&fast!=null)
        {
            fast=fast.next;
        }
        while(fast.next!=null)
        {
            fast=fast.next;
            slow=slow.next;
        }
        slow.next=slow.next.next;
        return dummyHead.next;      
    }
}

题目要求倒数第N个节点,所以先让快指针Fast先走N个节点,然后Slow和Fast再一起向后走,直到Fast来到了尾结点,此时Slow所在的节点则是倒数第N个节点,直接让Slow的后一个节点指向Slow.next.next即可删除要求节点。

面试题02.07. 链表相交

public class Solution {
    public ListNode GetIntersectionNode(ListNode headA, ListNode headB) {
        ListNode tmpA=headA;
        ListNode tmpB=headB;
        ListNode curA=headA;
        ListNode curB=headB;
        int n=0;
        if(headA==null|headB==null)
        {
            return null;
        }
        while(curA.next!=null)
        {
            n++;
            curA=curA.next;
        }
        while(curB.next!=null)
        {
            n--;
            curB=curB.next;
        }
        if(curA!=curB)
        {
            return null;
        }
        curA=n>0?headA:headB;
        curB=curA==headA?headB:headA;
        n=Math.Abs(n);
        while(n!=0)
        {
            n--;
            curA=curA.next;
        }
        while(curA!=curB)
        {
            curA=curA.next;
            curB=curB.next;
        }
        return curA;
    }
}

代码很长,但思路并不复杂,首先排除两个空链表的情况,然后遍历两个链表确定尾结点都是同一个则说明有相交,然后如果两个链表长度存在差值则让长的链表先走差值的长度,此时两个链表到尾节点的长度相同,两个链表均向尾结点遍历,在遍历过程中如果遍历到的节点相同,则这个节点是第一次相交的节点,返回当前节点即可。

142.环形链表II 

快慢指针法:

public class Solution {
    public ListNode DetectCycle(ListNode head) {
        ListNode slow=head.next;
        ListNode fast=head.next.next;
        while(slow!=fast)
        {
            if(fast.next==null|fast.next.next==null)
            {
                return null;
            }
            slow=slow.next;
            fast=fast.next.next;
        }
        slow=head;
        while(slow!=fast)
        {
            slow=slow.next;
            fast=fast.next;
        }
        return slow;
    }
}

因为我们采用循环条件就是Slow等于Fast的时候跳出,所以一开始Slow置于Head.next,Fast置于Head.next.next,然后Fast指针一次走两步,Slow指针一次走一步,有环则必有两个指针相等的时候,相等时候将Slow指针重置于Head处,然后Slow指针和Fast指针一次走一步,这次相遇的节点则是环形链表的入环点,虽然很玄学,但数学证明是可以证明的,感兴趣的小伙伴可以在评论区证明一下!

你可能感兴趣的:(算法,链表,c#)