Leetcode 876.求链表的中间节点

Leetcode 876.求链表的中间节点

一、题目描述

难度: easy 标签:链表

给定一个带有头结点 head 的非空单链表,返回链表的中间结点。

如果有两个中间结点,则返回第二个中间结点。

示例 1:

输入:[1,2,3,4,5]
输出:此列表中的结点 3 (序列化形式:[3,4,5])
返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。
注意,我们返回了一个 ListNode 类型的对象 ans,这样:
ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.

示例 2:

输入:[1,2,3,4,5,6]
输出:此列表中的结点 4 (序列化形式:[4,5,6])
由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点。

二、自己的解法

这是一道较为基础的链表题,解决的思路有很多种,最容易想到的便是:利用两个指针,一前一后,前面的指针每次走两步,后面的指针每次走一步,前面的指针到达链表末尾时,后面的指针则指向链表中间节点。

实现代码如下:

private static ListNode middleNode(ListNode head){
    ListNode forward = head;
    ListNode back = head;

    while (back != null && back.next != null) {
        forward = forward.next;
        back = back.next.next;
    }
    return forward;
}

复杂度分析: 只遍历了一次链表,因此时间复杂度是 O(n),并且只使用了常数量级的空间,因此空间复杂度是 O(1).

运行结果: 空间和时间均击败 100 %,是一个很不错的解法。

三、官方题解

1. 将链表输出至数组中

思路非常的简单,遍历一次链表,将链表放到数组中,然后根据下标求数组的中间位置的节点,代码如下:

public ListNode middleNode(ListNode head) {
    ListNode[] A = new ListNode[100];
    int t = 0;
    while (head.next != null) {
        A[t++] = head;
        head = head.next;
    }
    return A[t / 2];
}

另外我还想到了一种方式,那就是将链表节点存储到 Map 中,key 是下标, value 是节点,然后根据 k 的值去查对应的节点,和上面的思路是一样的,只是存放节点的容器不一样,代码如下:

private static ListNode middleNode(ListNode head){
    Map map = new HashMap<>();
    int k = 1;

    while (head != null){
        map.put(k++, head);
        head = head.next;
    }

    return map.get((k + 1) / 2);
}

复杂度分析: 还是只遍历了一次链表,因此时间复杂度是 O(n)。利用了额外的数组或者 Map,容量是链表节点的长度,所以空间复杂度也是 O(n)。

运行结果: 时间和空间均击败 100%。

2. 快慢指针

这就是我上面提到的自己的解法,思路稍微有一些巧妙,总体来说是最优解。

你可能感兴趣的:(Leetcode,Leetcode)