Day 04 继续链表

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

class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode hhead=new ListNode(0,head);
        ListNode p=head;
        ListNode pre=hhead;
        //p指针指的该节点与下一个节点交换,然后 pre=p,p=p.next
        //p.next==null 就结束
        while(p!=null&&p.next!=null){
            //记录下一个节点
            ListNode q=p.next;
            //交换
            pre.next=q;
            p.next=q.next;
            q.next=p;
            //移指针
            pre=p;
            p=p.next;
        } 
        return hhead.next;
    }
}

这题采用了虚拟头节点,是因为在交换头节点和头节点的下一个节点时头节点会变,使用虚拟头节点就避免头节点变化导致的多余代码。

这题的思想是,记录一下p节点前的节点pre和下一个节点q 交换就是将q节点的下一个节点赋给q,而将q赋给pre.next 将q的next再指向p即可。

这个时候p将会作为第二个节点。

所以当我们记录p指针位置为下一个交换的pre,将p指针指向next 一次交换就结束了。

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

暴力解法

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        //删除倒数第n个节点
        //暴力解法 记录链表长度,然后直接删除下标为(长度-n)的节点
        ListNode hhead=new ListNode(0,head);
        int length=0;
        ListNode p=head;
        while(p!=null){
            p=p.next;
            length++;
        }
        int index=length-n;
        p=hhead;
        for(int i=0;i<index;i++){
            p=p.next;
        }
        p.next=p.next.next;
        return hhead.next;
    }
}

没啥好说的,记录链表长度,计算出正向的下标然后删除即可

快慢指针

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        //快慢指针来解决
        //使用虚拟头节点
        //先让快指针走n下
        //然后慢指针和快指针一起再走,当fast.next==null时停下
        //这时慢指针的位置就是删除位置的上一个位置
        ListNode hhead=new ListNode(0,head);
        ListNode fast=hhead;
        ListNode slow=hhead;
        for(int i=0;i<n;i++){
            fast=fast.next;
        }
        while(fast.next!=null){
            fast=fast.next;
            slow=slow.next;
        }
        //删除
        slow.next=slow.next.next;
        return hhead.next;

    }
}

让快指针先走n步,然后快慢指针一起走,当快指针走到尾(fast.next==null)时slow指针刚好停在待删除节点的上一个节点。然后删除即可。

递归解法

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode hhead=new ListNode(0,head);
        delete(hhead,n);
        return hhead.next;
        //删除倒数第n个节点,递归写法

    }
    public int delete(ListNode head,int n){
        if(head==null){
            return n;
        }
        int ans=delete(head.next,n);
        if(ans==0){head.next=head.next.next;}
        return ans-1   ;
    }
}

这个挺有意思的,头递归,然后看自己是不是倒数第N个节点的上一个节点,如果是就删除自己的下一个节点,通过一个值ans去判断。

面试题02.07.链表相交

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if(headA==null||headB==null){return null;}
        ListNode pa=headA;
        ListNode pb=headB;
        int flag=2;
        while(pa!=pb){
            pa=pa.next;
            pb=pb.next;
            if(pa==null&&flag!=0){
                pa=headB;
                flag=flag-1;
            }if(pb==null&&flag!=0){
                pb=headA;
                flag=flag-1;
            }if(flag==0&&(pa==null||pb==null)){
                return null;
            }
        }
        return pa;
    }
}

这个题思路很简单,实现比较麻烦。

两条链表判断是否相交,只需要用两个指针同时跑链表即可,当有一个指针跑到末尾时换到另外一条链表上,若其中一个跑完了两条链表但是还是没有和另外一个指针相遇说明两条链表没有相交,若两个指针相遇,则该位置就是交点。

经过分析可知,若两条链表相交,则当分别遍历两条链表非相交部位时进行交换,这样使得两个节点走过的路程是一样的,当他两相遇时,相当于都走过了非相交部分的长度和一条相交部分的长度。自然就会在相交位置停下来。

在实现上,其目标就是让pa和pb在同一个位置然后停下来,所以我采用的判断条件为pa!=pb。当pa第一次==null时,应把其挪到headB上,pb第一次==null时,应把他挪到headA上,这两个操作一定会在pa二次==null或者pb第二次==null或者pa==pb之前的,所以使用一个flag来计数。当出现这两个第一次以外的事件的时候 直接返回。

142.环形链表Ⅱ

public class Solution {
    public ListNode detectCycle(ListNode head) {
        if(head==null){return null;}
        //快慢指针判环然后 同速指针找相交点
        ListNode fast=head;
        ListNode slow=head;
        int flag=1;
        while(fast!=slow||flag==1){
            if(flag==1) flag=0;
            if(fast.next==null||fast.next.next==null) return null;
            fast=fast.next.next;
            slow=slow.next;
        }
        //没有被返回就是有环
        fast=head;
        while(fast!=slow){
            fast=fast.next;
            slow=slow.next;
        }
        return fast;
    }
}

快慢指针来判断是否有环,若有环,再使用同步指针来判断环的位置,这个题是一个数学题。个人觉得记住就行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值