LeetCode

203. 移除链表元素

删除链表中等于给定值 val 的所有结点。

思路:
删除结点这件事情很可能发生在链表的头结点,因此需要对头结点特殊处理。
递归,首先处理递归到底的情况,直接返回 null。假设下一个结点开始的链表已经处理完了。再将头结点和除了头结点以外的链表部分合并考虑。

执行用时:1 ms, 在所有 Java 提交中击败了99.84%的用户。

  1. class Solution {
  2. public ListNode removeElements(ListNode head, int val) {
  3. ListNode dummy = new ListNode(0);
  4. dummy.next = head;
  5. ListNode cur = dummy;
  6. while (cur.next != null) {
  7. if (cur.next.val == val) {
  8. cur.next = cur.next.next;
  9. } else {
  10. cur = cur.next;
  11. }
  12. }
  13. return dummy.next;
  14. }
  15. }
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        if (head == null) {
            return head;
        }

        ListNode res = removeElements(head.next, val);
        if (head.val == val) {
            return res;
        } else {
            head.next = res;
            return head;
        }
    }
}

21. 合并两个有序链表

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

思路:
比较大小然后合并,注意递归和非递归两种方法。

执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户。

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(l2.next, l1);
            return l2;
        }
    }
}
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode dummy = new ListNode(-1);
        ListNode newhead = dummy;
        while(l1 != null && l2 != null) {
            if(l1.val < l2.val) {
                newhead.next = l1;
                l1 = l1.next;
            } else {
                newhead.next = l2;
                l2 = l2.next;
            }
            newhead = newhead.next;
        }
        if(l1 != null) {
            newhead.next = l1;
        } else {
            newhead.next = l2;
        }
        return dummy.next;
    }
}

练习:

82. 删除排序链表中的重复元素 II

剑指 Offer

剑指 Offer 18. 删除链表的节点

给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。
返回删除后的链表的头节点。
注意:此题对比原题有改动

思路:
①链表。题目说了没有重复的值,先判断开头节点是否是我们要删除的,再开始遍历,如果遇到要删除的节点,分这个节点的下一个节点是否为null讨论。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode deleteNode(ListNode head, int val) {
        if (head.val == val) {
            return head.next;
        }
        ListNode dummy = head;
        while (dummy.next != null) {
            ListNode temp = dummy.next;
            if (temp.val == val) {
                if (temp.next != null) {
                    dummy.next = temp.next;
                } else {
                    dummy.next = null;
                }
                break;
            }
            dummy = dummy.next;
        }
        return head;
    }
}

②双指针。

class Solution {
    public ListNode deleteNode(ListNode head, int val) {
        //初始化一个虚拟节点
        ListNode dummy = new ListNode(0);
        //让虚拟节点指向头结点
        dummy.next = head;
        ListNode cur = head;
        ListNode pre = dummy;
        while (cur != null) {
            if (cur.val == val) {
                //如果找到要删除的结点,直接把他删除
                pre.next = cur.next;
                break;
            }
            //如果没找到,pre指针和cur指针都同时往后移一步
            pre = cur;
            cur = cur.next;
        }
        //最后返回虚拟节点的下一个结点即可
        return dummy.next;
    }
}

③递归。

class Solution {
    public ListNode deleteNode(ListNode head, int val) {
        //边界条件判断
        if (head == null)
            return head;
        //如果要删除的是头结点,直接返回头结点的下一个结点即可
        if (head.val == val)
            return head.next;
        ListNode cur = head;
        //找到要删除结点的上一个结点
        while (cur.next != null && cur.next.val != val) {
            cur = cur.next;
        }
        //删除结点
        cur.next = cur.next.next;
        return head;
    }
}

剑指 Offer 35. 复杂链表的复制

请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null

思路:
1.复制每个节点。
2.复制随机节点。dummy.random.next而不是dummy.random,因为要指向之前复制的节点,不能指向原节点
3.拆分链表。

/*
// Definition for a Node.
class Node {
    int val;
    Node next;
    Node random;

    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}
*/
class Solution {
    public Node copyRandomList(Node head) {
        if (head == null) {
            return head;
        }

        Node dummy = head;
        while (dummy != null) {
            Node clone = new Node(dummy.val);
            Node next = dummy.next;
            dummy.next = clone;
            clone.next = next;
            dummy = next;
        }

        dummy = head;
        while (dummy != null) {
            dummy.next.random = dummy.random == null ? null : dummy.random.next;
            dummy = dummy.next.next;
        }

        dummy = head;
        Node cloneHead = head.next;
        while (dummy != null) {
            Node clone = dummy.next;
            dummy.next = clone.next;
            clone.next = clone.next == null ? null : clone.next.next;
            dummy = dummy.next;
        }

        return cloneHead;
    }
}