刷题day4 24两两交换链表中的节点、19删除链表的倒数第N个节点、面试题-链表相交、142环形链表

一、两两交换链表中的节点

这道题主要是设置一个虚拟头节点ListNode dummyhead = new ListNode(-1);之后再创建一个指向虚拟头结点的指针cur,再将虚拟头结点和头节点连起来cur.next = head;之后创建一个临时指针(指向第三个节点),还有指向第一个节点的指针,指向第二个节点的指针

再进行while循环,循环条件是不能是没有节点并且不能是一个节点(cur.next!=null && cur.next.next!=null)

之后就是循环,将创建的指针分别指向虚拟指针之后的对应 第一、第二、第三个节点,这都是用cur.next表示的,为的是每次最后移动cur到下一轮的时候,这三个指针也会自动移动到下一轮的位置,因为是都是基于cur.next来创建的

然后就是节点的断链和重新指向的赋值(三步),之后将cur指向最后交换的位置firstNode,继续做下一轮的交换,

最后循环结束,返回新的头节点,也就是之前创建的虚拟头节点的next:dummy.next

代码如下:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode swapPairs(ListNode head) {
            ListNode dummyhead = new ListNode(-1);
            ListNode cur = dummyhead;
            dummyhead.next = head;
            ListNode temp;
            ListNode firstNode;
            ListNode secondNode;
            while(cur.next!=null && cur.next.next!=null )
            {
                firstNode = cur.next;
                secondNode = cur.next.next;
                temp = cur.next.next.next;
                cur.next = secondNode;
                secondNode.next = firstNode;
                firstNode.next = temp;
                cur = firstNode;
            }
            return dummyhead.next;         
    }
}

二、删除链表的倒数第N个节点

这道题主要是考察一个虚拟头节点还有双指针的应用,先定义一个虚拟头节点还有两个快慢指针,虚拟头节点的next指向头节点,两个指针都指向虚拟头节点

明白题目给定的n和咱们快慢指针的移动的关系,首先先让快指针移动n+1步【因为只有这样同时移动的时候slow才能指向删除节点的上一个节点(方便做删除操作)】 因为这样快慢指针中间的距离会控制在n,在之后快慢指针一起向后移动的时候,那么在快指针指向最后null位置的时候,慢指针与快指针之间的距离是n所以慢指针指向的位置就是倒数第n个位置,这时你会发现慢指针的next即为待删的倒数第n个节点,之后直接进行节点删除的正常操作。

代码如下:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode virtue = new ListNode(-1);
        ListNode fast;
        ListNode slow;
        virtue.next = head;
        fast = virtue;
        slow = virtue;
        for(int i = 0;i<n+1;i++)
        {
            fast = fast.next;
        }
        while(fast != null)
        {
            fast = fast.next;
            slow = slow.next;
        }

        slow.next = slow.next.next;
        return virtue.next;
    }
}

三、面试题-链表相交

首先这道题主要是找到规律,题目给定的都是在相交节点之后,a和b两个链表的数值都相同

所以先把两链表的尾巴对齐,然后要让a链表的头结点指针先移动lena-lenb的长度,这时就要求出a、b两个链表的长度,这里用while循环,但是最后出了循环别忘了,nodea和nodeb要同时再指回原来的a、b头结点指针

移动lena-lenb的长度后,这时a的结点指针与b的头结点指针对齐了,之后两指针同时向后移动,如果a和b的指针相同,那么代表这个位置是交点,返回nodea(或nodeb),否则返回的是空null【考虑的情况都是lena>lenb的情况,所以中间还要做一个lenb>lena的转换,将a的长度移动到b的长度,将a的头结点指针移动到b的头结点指针处,反之,将b的值和头结点指针都移动到a的地方,这样处理完之后还是相当于是lena>lenb】

代码如下:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode nodea = headA;
        ListNode nodeb = headB;
        int lena = 0;
        int lenb = 0;
        while(nodea != null)
        {
            lena++;
            nodea = nodea.next;
        }
        while(nodeb != null)
        {
            lenb++;
            nodeb = nodeb.next;
        }
        nodea = headA;
        nodeb = headB;
        if(lenb > lena)
        {
            int tempt = lena;
            lena = lenb;
            lenb = tempt;
            ListNode temp = nodea;
            nodea = nodeb;
            nodeb = temp;
        }
        int gep = lena - lenb;
        while(gep-- > 0)
        {
            nodea = nodea.next;
        }
        while(nodea != null)
        {
            if(nodea == nodeb)
            {
                return nodea;
            }
            nodea = nodea.next;
            nodeb = nodeb.next;
        }
        return null;
    }
}

四、环形链表II

这道题首先要明白,设置双指针,一快一慢,快指针走两个节点 ,慢指针走一个节点,如果有环的话一定会有相遇点

找到相遇点后,我们需要推出来,从头出发和从相遇点出发,这次是每个指针都是走的一个节点,之后相遇的点就是环的入口,这里需要简单的推导一下

假设从头结点到环形入口节点 的节点数为x。 环形入口节点到 fast指针与slow指针相遇节点 节点数为y。 从相遇节点 再到环形入口节点节点数为 z。 如图所示:

之后就是在第一次相遇后,为什么要写if(fast != null&& fast.next != null)?

答:为什么需要判断 fast != null 呢?这是因为当快指针(fast)在遍历链表时,如果它能够成功遍历到链表的末尾,那么说明链表没有环。因此,循环的终止条件是 fast != null

之后在if条件里再while头部指针和相遇节点再次移动一个节点,找到相等时即是环的入口

最后如果第一个while之后还没有找到环入口,那么就是返回的是null(题上的条件)

这道题要注意的点有两个:首先要定义快慢指针都从头节点开始,每次快指针向后移动两个单位,慢指针向后移动一个单位,如果有环的话他们一定会相遇的,这是一个定理,之后在相遇的时候又定义了一个头节点开始的指针,一个相遇点的指针,然后两个一起向后移动,如果能相遇的话,说明这是环的入口,这个也是一个定理,是推导出来的,不管那个相遇点转几圈,他都会和从头开始的指针在环的入口相见

代码如下:

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fast;
        ListNode slow;
        fast = head;
        slow = head;
        while(fast.next != null&&fast.next.next != null)
        {
            slow = slow.next;
            fast = fast.next.next;
            if(fast == slow)
            {
                ListNode index1 = head;
                ListNode index2 = fast;
                while(index1 != index2)
                {
                    index1 = index1.next;
                    index2 = index2.next;
                }
                return index2;
            }
        }
        return null;
    }
}

五、总结

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值