《剑指offer》 -day12- 双指针(简单)

剑指 Offer 25. 合并两个排序的链表

题目描述

输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。


限制:

  • 0 < = 链 表 长 度 < = 1000 0 <= 链表长度 <= 1000 0<=<=1000

双指针

思路:采用归并排序思想

  • 设指针pq分别指向链表 l 1 l1 l1 l 2 l2 l2 当前待处理节点;
  • 每次比较 p.valq.val,将较小者对应的节点添加到 新链表中;
  • 若经过一轮比较后(即,退出while时),l1l2 中仍然有剩余节点(二者只会有一个有剩余),则将剩余节点“接到”新链表 末尾。
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode p = l1;
        ListNode q = l2;
        ListNode ansList = new ListNode(); // 虚拟头结点\
        ListNode cnt = ansList; // 新链表的当前节点
        while (p != null && q != null) {
            if (p.val < q.val) {
                cnt.next = p;
                cnt = cnt.next;
                p = p.next;
            } else {
                cnt.next = q;
                cnt = cnt.next;
                q = q.next;
            }
        }
        // 剩余部分直接修改指针,即可
        if (p != null) cnt.next = p;
        if (q != null) cnt.next = q;
        return ansList.next;
    }
}
  • 时间复杂度: O ( m + n ) O(m + n) O(m+n)
  • 空间复杂度: O ( 1 ) O(1) O(1)
    双指针

递归 🔥

参考 题解(注意动画演示)

思路 🤔

  1. 终止条件
    • 如果 l 1 l1 l1 为空,则返回 l 2 l2 l2
    • 如果 l 2 l2 l2 为空,则返回 l 1 l1 l1
  2. 递归体
    比较两个节点,使用二者 v a l val val 较小者,继续递归。
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        // 终止条件
        if (l1 == null) return l2;
        if (l2 == null) return l1;
        // 递归体
        if (l1.val < l2.val) {
            l1.next = mergeTwoLists(l1.next, l2);
            return l1;
        } else {
            l2.next = mergeTwoLists(l1, l2.next);
            return l2;
        }
    }
}

递归

剑指 Offer 52. 两个链表的第一个公共节点

题目描述

输入两个链表,找出它们的第一个公共节点。


注意:

  • 如果两个链表没有交点,返回 n u l l null null.
  • 在返回结果后,两个链表仍须保持原有的结构。
  • 可假定整个链表结构中没有循环。
  • 程序尽量满足 O ( n ) O(n) O(n) 时间复杂度,且仅用 O ( 1 ) O(1) O(1) 内存。

哈希

思路:

  • 使用 set 保存 headA 所有节点;
  • 遍历 headB 中所有节点 q:
    • 若 q 在 set 中,则说明 q 为为 两个链表的“交点”;
    • 否则,如果所有 q 都不在 s e t set set,说明二者无“交点”
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        Set<ListNode> set = new HashSet<>();
        ListNode p = headA;
        // 将 headA 所有节点添加到 set
        while (p != null) {
            set.add(p);
            p = p.next;
        }
        ListNode q = headB;
        while (q != null) {
            if (set.contains(q)) {
                return q;
            }
            q = q.next;
        }
        return null;
    }
}
  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n)
    哈希

双指针 ⭐️

使用“哈希表”的解法可以进一步优化,将空间复杂度降为 O ( 1 ) O(1) O(1).

思路 🤔

  1. 分别求两个链表的长度;
  2. 保证 headA 是长度更长的那个;
  3. 尾对齐”:将 headA 向后移动 l e n A − l e n B lenA - lenB lenAlenB 个节点(保证两个链表“尾对齐”)
  4. 双指针 h e a d A headA headA h e a d B headB headB 同时后移
    • headA == headB,说明找到“交点”;
    • 否则,无“交点”
/**
 * 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) {
        // 1、求两个链表长度
        int lenA = getLength(headA);
        int lenB = getLength(headB);
        // 2、保证headA是短链表
        if (lenA > lenB) {
            // 交换长度
            lenA = lenA ^ lenB;
            lenB = lenA ^ lenB;
            lenA = lenA ^ lenB;
            // 交换链表
            ListNode temp = headA;
            headA = headB;
            headB = temp;
        }
        // 3、对齐尾节点:headB向后移动(lenB - lenA)个节点
        int offset = lenB - lenA;
        while (offset-- > 0) {
            headB = headB.next;
        }
        // 4、同时遍历headA、headB
        while (headB != null) {
            if (headA == headB) {
                return headB;
            }
            headA = headA.next; // 同时后移
            headB = headB.next;
        }
        return null; // 无交点
    }

    int getLength(ListNode head) {
        int len = 0;
        while (head != null) {
            len++;
            head = head.next;
        }
        return len;
    }
}
  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( 1 ) O(1) O(1)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值