LeetCode203. 移除链表元素(链表的应用)

203.移除链表元素

这是LeetCode第203号问题,题目链接:https://leetcode-cn.com/problems/remove-linked-list-elements/

删除链表中等于给定值 val 的所有节点。
示例:
输入: 1->2->6->3->4->5->6, val = 6
输出: 1->2->3->4->5

ListNode.java

LeetCode中提供的节点,为了本地测试方便,添加方法进行完善。

public class ListNode {
    int val;
    ListNode next;

    ListNode(int x) {
        val = x;
    }

    public ListNode(int[] arr) {
        if (arr == null || arr.length == 0)
            throw new IllegalArgumentException("arr can not be empty");
        // val 等于第一个元素
        this.val = arr[0];

        // 把数组中元素创建成一个个新的ListNode接在前一个节点上
        ListNode cur = this;
        for (int i = 1; i < arr.length; i++) {
            cur.next = new ListNode(arr[i]);
            cur = cur.next;  // 挪位置
        }
        // 之后this就是用循环创建的链表的头节点
    }

    // 返回以当前节点为头节点的字符串
    @Override
    public String toString() {
        StringBuilder res = new StringBuilder();
        ListNode cur = this;
        while (cur != null) {
            res.append(cur.val + "-->");
            cur = cur.next;
        }
        res.append("NULL");
        return res.toString();

    }
}

不使用虚拟头节点

按照思路一步一步实现

// 不创建虚拟头节点
class Solution {
    public ListNode removeElements(ListNode head, int val) {

        // 如果头节点是待删除元素,需要删除
        // 使用一个循环删除,存在头节点后一个元素也是需要删除的
        while (head != null && head.val == val) {  // 头节点不能为空
            ListNode delNode = head;
            head = head.next;
            delNode.next = null;  // 断开链接
        }

        if (head == null) {
            return null;
        }

        // 从中间删,此时head一定不是待删除元素,head后一个节点可能是带删除元素
        ListNode prev = head;  // prev为待删除元素前一个元素
        while (prev.next != null) {
            if (prev.next.val == val) {
                ListNode delNode = prev.next;
                prev.next = delNode.next;
                delNode.next = null;
            } else {
                // 否则的话不用删除,往回偏移
                prev = prev.next;
            }
        }
        return head;
    }
}

上述代码简写

class Solution {
    public ListNode removeElements(ListNode head, int val) {

        // 如果头节点是待删除元素,需要删除
        // 使用一个循环删除,存在头节点后一个元素也是需要删除的
        while (head != null && head.val == val) {  // 头节点不能为空
            head = head.next;
        }

        if (head == null) {
            return null;
        }

        // 从中间删,此时head一定不是待删除元素,head后一个节点可能是带删除元素
        ListNode prev = head;  // prev为待删除元素前一个元素
        while (prev.next != null) {
            if (prev.next.val == val) {
                prev.next = prev.next.next;
            } else {
                // 否则的话不用删除,往回偏移
                prev = prev.next;
            }
        }
        return head;
    }

使用虚拟头节点

// 使用虚拟头节点
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        ListNode dummyHead = new ListNode(-1);  // 随便给一个,永远不会访问到
        dummyHead.next = head;  // 不需要对第一个节点进行特殊处理

        ListNode prev = dummyHead;
        while (prev.next != null) {
            if (prev.next.val == val)
                prev.next = prev.next.next;
            else
                prev = prev.next;
        }
        return dummyHead.next;
    }
}

链表具有递归性质

把一个一个节点连接起来就是一个链表
对于链表0->1->2->3->4->5->NULL,可以想像成0->和一个更短的链表(少了一个节点),链表可以理解为一个一个节点的挂接,也可以理解成一个头节点后面挂接了一个更小的链表。

  • 在这个更短的链表中,“1”就变成了它的头节点。
  • 更短的链表也可以类似的看作头节点“1”挂接了一个比现在更小的链表,在这个更小的链表中,“2”作为它的头节点。
  • 依此类推,直到最后,可以理解NULL本身也是一个链表,它也是最基本的链表。

使用递归删除链表中的元素

class Solution {
    public ListNode removeElements(ListNode head, int val) {

        // 对于空链表删除所有元素为val的节点,得到的还是空
        if (head == null)
            return null;
        // 将头节点后的链表中所有的val值删除后剩下的链表
        ListNode res = removeElements(head.next, val);
        // 判断头节点的值是否为val
        if (head.val == val)
            return res;
        // head的值不为val时候返回head和后面的链表
        else {
            // 让head挂接上后面的链表
            head.next = res;
            return head;
        }
    }
}

代码简写

// 使用递归来解决
class Solution5 {
    public ListNode removeElements(ListNode head, int val) {
        // 对于空链表删除所有元素为val的节点,得到的还是空
        if (head == null)
            return null;
        // 将头节点后的链表中所有的val值删除后剩下的链表
        head.next = removeElements(head.next, val);
        // 三目运算符简写
        return (head.val == val) ? head.next : head;
    }
}

书写测试主函数

public static void main(String[] args) {
    int[] arr = {1, 2, 6, 3, 4, 5, 6};
    ListNode list = new ListNode(arr);
    System.out.println(list);
    ListNode res = (new Solution()).removeElements(list, 6);
    System.out.println(res);
}

测试结果

1-->2-->6-->3-->4-->5-->6-->NULL
1-->2-->3-->4-->5-->NULL

猜你喜欢

转载自blog.csdn.net/wankcn/article/details/105521693