算法系列-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;
    }

你可能感兴趣的:(算法,java)