算法系列-力扣876-求链表的中间节点

# 求链表中间节点,如果有两个中间节点取后面那个

链表定义

```

// @lc code=start

/**

 * Definition for singly-linked list.

 * public class ListNode {

 *     int val;

 *     ListNode next;

 *     ListNode() {}

 *     ListNode(int val) { this.val = val; }

 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }

 * }

 */

```

方法一:计数取一半

解题方法:

先计算链表一共有多少个节点n

n/2,得到中间节点的下标(从0开始)

1 -> 2 -> 3 -> 4 -> 5

坐标节点就是链表的中间节点

时间复杂度:O(n)

空间复杂度:O(1)

```

    public ListNode middleNode(ListNode head) {

        /**

         * 先计算链表一共有多少个节点n

         * n/2,得到中间节点的下标(从0开始)

         *  1 -> 2 -> 3 -> 4 -> 5

         *  坐标节点就是链表的中间节点

         * */

        int n=0;

        ListNode p=head;

        while (p!=null){

            n++;

            p=p.next;

        }

        int mid=n/2;

        ListNode midNode=head;

        for (int i = 0; i < mid; i++) {

            midNode=midNode.next;

        }

        return midNode;

    }

```

方法二:双指针

解题方法:

定义快慢两个指针,快指针每次移动2步,慢指针每次移动1步

注意:指针需要从头节点前开始移动,因此需要定义一个哑结点,快指针和慢指针都从哑节点开始

当快指针移动了2k步后,慢指针移动了k步

假设2k=n,k=n/2

当n为偶数时,慢指针的后续节点就是中间节点

当n为奇数时,慢指针就是中间节点

是否是偶数节点看快指针每次是否都能移动两步

时间复杂度:O(n)

空间复杂度:O(1)

```

    public ListNode middleNode(ListNode head) {

        /**

         * 定义快慢两个指针,快指针每次移动2步,慢指针每次移动1步

         * 注意:指针需要从头节点前开始移动,因此需要定义一个哑结点,快指针和慢指针都从哑节点开始

         * 当快指针移动了2k步后,慢指针移动了k步

         * 假设2k=n,k=n/2

         * 当n为偶数时,慢指针的后续节点就是中间节点

         * 当n为奇数时,慢指针就是中间节点

         * 是否是偶数节点看快指针每次是否都能移动两步

         * -1 -> 1 -> 2 -> 3 -> 4 -> 5 -> null

         * -1 -> 1 -> 2 -> 3 -> 4 -> null

         * */

        if(head == null){

            return null;

        }

        ListNode dummy = new ListNode(-1);

        dummy.next=head;

        ListNode slow=dummy;

        ListNode fast=dummy;

        ListNode midNode=null;

        Boolean isEvent=true;

        while (fast.next!=null){

            slow=slow.next;

            if(fast.next.next!=null) {

                fast = fast.next.next;

            } else{

                fast=fast.next;

                isEvent=false;

            }

        }

        midNode = isEvent ? slow.next : slow;

        return  midNode;

    }

```

方法三:双指针优化

解题方法:

定义快慢两个指针,快指针每次移动2步,慢指针每次移动1步

快指针和慢指针都从头节点开始移动

当快指针移动到链尾时,慢指针移动了k步,n>1

当n为偶数时,n-1必然是奇数

即快指针移动了2(k-1)+1步

此时快慢指针距离原点距离

快2(k-1)+1+1  简化  2k

慢k+1

即慢指针正好处于链表中间位置。

当n为奇数时,n-1必然是偶数

,快指针移动了2k步

此时快慢指针距离原点距离

2k+1

k+1

即慢指针正好处于链表中间位置

时间复杂度:O(n)

空间复杂度:O(1)

方法二的本质是下面的公式:

偶数

快2k

慢k

中间k+1

奇数

快2k-1

慢k

中间k

即快慢指针的初始位置+1就把公式统一了。

```

    public ListNode middleNode(ListNode head) {

        if(head == null){

            return null;

        }

        ListNode slow=head;

        ListNode fast=head;

        

        while (fast!=null && fast.next!=null){

            slow=slow.next;

            fast = fast.next.next;

        }

      

        return slow;

    }

```

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值