day 6:走进链表世界

77 阅读2分钟
  • 链表的处理:合并、删除等(删除操作画个记号,重点中的重点!)

链表合并

真题描述:将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有结点组成的。 

示例: 输入:1->2->4, 1->3->4 输出:1->1->2->3->4->4

链表处理的问题的中心思想——本质就是处理链表结点之间的指针关系!!!

思路分析↓

1662343248859.png

两个链表合并——补齐双方之间的节点next指针关系

image.png

const mergeTwoLists = function (l1, l2) {
    // 定义头结点,确保链表可以被访问到
    let head = new ListNode()
    // cur 这里就是咱们那根“针”
    let cur = head
    // “针”开始在 l1 和 l2 间穿梭了
    while (l1 && l2) {
        // 如果 l1 的结点值较小
        if (l1.val <= l2.val) {
            // 先串起 l1 的结点
            cur.next = l1
            // l1 指针向前一步
            l1 = l1.next
        } else {
            // l2 较小时,串起 l2 结点
            cur.next = l2
            // l2 向前一步
            l2 = l2.next
        }

        // “针”在串起一个结点后,也会往前一步
        cur = cur.next

    }

    // 处理链表不等长的情况
    cur.next = l1 !== null ? l1 : l2
    // 返回起始结点
    return head.next
};

结点删除

真题描述:给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。

示例 1:
输入: 1->1->2
输出: 1->2
示例 2:
输入: 1->1->2->3->3
输出: 1->2->3

思路分析:
① 考察链表的遍历(while循环)
② 判断两个元素是否重复 image.png

const deleteDuplicates = function (head) {
    // 设定 cur 指针,初始位置为链表第一个结点
    let cur = head;
    // 遍历链表
    while (cur != null && cur.next != null) {
        // 若当前结点和它后面一个结点值相等(重复)
        if (cur.val === cur.next.val) {
            // 删除靠后的那个结点(去重)
            cur.next = cur.next.next;
        } else {
            // 若不重复,继续遍历
            cur = cur.next;
        }
    }
    return head;
};

dummy 结点登场

dummy 结点,就是我们人为制造出来的第一个结点的前驱结点,这样链表中所有的结点都能确保有一个前驱结点。

真题描述:给定一个排序链表,删除所有含有重复数字的结点,只保留原始链表中 没有重复出现的数字。

示例 1:
输入: 1->2->3->3->4->4->5
输出: 1->2->5
示例 2:
输入: 1->1->1->2->3
输出: 2->3

思路分析:

利用dummy结点制造出前驱结点,然后和后继结点对比,相同删除

const deleteDuplicates = function (head) {
    // 设定 cur 指针,初始位置为链表第一个结点
    let cur = head;
    // 遍历链表
    while (cur != null && cur.next != null) {
        // 若当前结点和它后面一个结点值相等(重复)
        if (cur.val === cur.next.val) {
            // 删除靠后的那个结点(去重)
            cur.next = cur.next.next;
        } else {
            // 若不重复,继续遍历
            cur = cur.next;
        }
    }
    return head;
};


// dummy结点
const deleteDuplicates = function (head) {
    // 极端情况:0个或1个结点,则不会重复,直接返回
    if (!head || !head.next) {
        return head
    }
    // dummy 登场
    let dummy = new ListNode()
    // dummy 永远指向头结点
    dummy.next = head
    // cur 从 dummy 开始遍历
    let cur = dummy
    // 当 cur 的后面有至少两个结点时
    while (cur.next && cur.next.next) {
        // 对 cur 后面的两个结点进行比较
        if (cur.next.val === cur.next.next.val) {
            // 若值重复,则记下这个值
            let val = cur.next.val
            // 反复地排查后面的元素是否存在多次重复该值的情况
            while (cur.next && cur.next.val === val) {
                // 若有,则删除
                cur.next = cur.next.next
            }
        } else {
            // 若不重复,则正常遍历
            cur = cur.next
        }
    }
    // 返回链表的起始结点
    return dummy.next;
};