代码随想录|链表|leetcode24,19,面试题0207,142

两两交换链表中的节点

/**
 * 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);
        dummyhead.next = head;
        ListNode cur = dummyhead;
        ListNode tmp;
        ListNode firstNode;
        ListNode secondNode;
        while(cur.next != null && cur.next.next!=null){
            tmp = cur.next.next.next;
            firstNode = cur.next;
            secondNode = cur.next.next;
            //step 1
            cur.next = secondNode;
            //step 2
            secondNode.next = firstNode;
            //step 3
            firstNode.next = tmp;
            //cur最后移动,准备下一轮交换
            cur = firstNode;

        }
        return dummyhead.next;

    }
}
  1. 创建一个虚拟头节点:

    • 使用虚拟头节点 dummyhead 可以简化边界条件,无需分别处理头节点和其他节点。
  2. 初始化指针:

    • cur 指针用于追踪当前需要交换的对的前一个节点。一开始指向 dummyhead
    • firstNodesecondNode 分别指向需要交换的两个节点。
    • tmp 用于临时存储第二节点后的节点。
  3. 交换操作:

    • 首先检查 cur 后是否有两个节点可以交换。
    • 使用 tmp 存储 secondNode 后的节点。
    • 进行三个交换步骤:
      1. cur.next 指向 secondNode
      2. secondNode.next 指向 firstNode
      3. firstNode.next 指向 tmp
    • 最后,将 cur 指针移动到 firstNode,为下一对节点做准备。
  4. 返回结果:

    • 返回 dummyhead.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 dummyhead = new ListNode(0);
        dummyhead.next = head;
        //定义两个指针
        ListNode fastIndex = dummyhead;
        ListNode slowIndex = dummyhead;
        for(int i = 0; i <n; i++){
            fastIndex = fastIndex.next;
        }
        while(fastIndex.next!=null){
            fastIndex = fastIndex.next;
            slowIndex = slowIndex.next;

        }
        //此时slowindex就是待删除的前一个元素
        slowIndex.next = slowIndex.next.next;
        return dummyhead.next;

    }
}

思路:

关键是找到待删除元素的前一个元素

  1. 创建一个虚拟头节点:

    • 使用虚拟头节点 dummyhead 可以简化边界条件,无需分别处理头节点和其他节点。例如,当链表只有一个节点或需要删除头节点时,这一点是非常有用的。
  2. 初始化双指针

    • fastIndexslowIndex 两个指针均从 dummyhead 开始。
    • 先移动 fastIndex 指针,使它领先 slowIndex 指针 n 步。
  3. 同时移动两个指针

    • fastIndexslowIndex 之间的间隔为 n 时,同时移动两个指针,直到 fastIndex 到达链表末尾。
    • 此时,slowIndex 指向待删除节点的前一个节点。
  4. 删除节点

    • 通过 slowIndex.next = slowIndex.next.next 来跳过待删除的节点,从而删除它。
  5. 返回结果

    • 返回 dummyhead.next,这是修改后链表的新头节点。

面试题 02.07. 链表相交 

/**
 * 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 curA = headA;
        ListNode curB = headB;
        int lenA = 0, lenB = 0;
        while(curA!=null){
            lenA++;
            curA = curA.next;
        }
        while(curB != null){
            lenB++;
            curB = curB.next;
        }
        curA = headA;
        curB = headB;
        if(lenB>lenA){
            int temp = lenA;
            lenA = lenB;
            lenB = temp;

            ListNode tmp = curA;
            curA = curB;
            curB = tmp;
        }

        int gap = lenA - lenB;
        while(gap>0){
            gap--;
            curA = curA.next;
        }
        while(curA!=null){
            if(curA == curB){
                return curA;
            }
            curA = curA.next;
            curB = curB.next;
        }
        return null;
        
    }
}

思路:

  1. 计算两个链表的长度

    • 遍历链表A和B,分别计算它们的长度为lenAlenB
  2. 找到长链表的起始点

    • 如果链表A比链表B长,则链表A的当前节点(curA)应向前移动lenA - lenB步,反之亦然。这样,两个链表就可以在同一起始点上对齐。
  3. 寻找交点

    • 现在,两个链表的长度相同,所以可以同时遍历两个链表,查看它们的节点是否相同。如果在遍历过程中找到相同的节点,那么这个节点就是交点。
    • 如果遍历结束都没有找到相同的节点,那么两个链表没有交点,返回null

此方法利用了“对齐”技巧。当两个链表的长度不同,且有交点时,那么较长链表的前几个节点不可能是交点。所以,可以安全地跳过它们,从而使两个链表长度相同。

这种方法的优势在于只需要遍历两次链表。第一次是计算长度,第二次是寻找交点。

 

环形链表II

/**
 * 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 fastIndex = head;
        ListNode slowIndex = head;
        while(fastIndex!=null && fastIndex.next!=null){
            fastIndex = fastIndex.next.next;
            slowIndex = slowIndex.next;
            if(slowIndex == fastIndex) { //相遇,证明有环
                ListNode index1 = fastIndex;
                ListNode index2 = head;
                // 两个指针,从头结点和相遇结点,各走一步,直到相遇,相遇点即为环入口
                while(index1 != index2){
                    index1 = index1.next;
                    index2 = index2.next;
                }
                return index1;
            }

        }
        return null;

        
    }
}

思路:

  1. 查找环:使用两个指针,一个快指针每次移动两个节点,一个慢指针每次移动一个节点。如果链表中存在一个环,那么快指针和慢指针最终会在某个节点上相遇。

  2. 查找环的入口:当快指针和慢指针相遇时,把快指针或慢指针重新放回头节点,然后每次移动快指针和慢指针一个节点,当它们再次相遇时,相遇的节点就是环的入口。

  • 首先,定义两个指针 fastIndexslowIndex,都初始化为头节点 head

  • 然后,通过一个 while 循环,使得 fastIndex 指针每次向前移动两个节点,而 slowIndex 指针每次向前移动一个节点。这是在寻找环的步骤。

  • 如果存在一个环,fastIndex 指针和 slowIndex 指针最终会相遇(在环内的某个位置)。

  • 当它们相遇时,你把其中一个指针(代码中是 slowIndex)重新设置为头节点。然后,再次移动两个指针,但这次每个指针都只移动一个节点,直到它们相遇。当它们相遇时,相遇的节点就是环的入口。

  • 如果 fastIndexfastIndex.next 中的任何一个为 null,这意味着链表没有环,因此返回 null

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值