题目如下:
这道题呢,这里我写出了两种解决办法,一种遍历链表来得出中间结点,一种通过快慢指针来得出中间结点
第一种:
遍历:
首先我们设置一个计数器count,来记录链表的长度,写一个函数来遍历链表,返回
count的一半的大小,即为这个链表的中间结点。(在代码的最前面,写一个typedef方便后续命名结构体)
typedef struct ListNode ListNode;
int lenl(ListNode* head){ListNode* tail=head;int count=0;while(tail){count++;tail=tail->next;}return count/2;}
我们获取了中间结点之后,我们只需要将头结点设置为这个中间结点就可以了
struct ListNode* middleNode(struct ListNode* head) {int len=lenl(head);while(len>0){head=head->next;len--;}return head;}
这里我们重点需要知道的是,while 的循环条件,len>=0还是len>0
分析;
如果我们循环条件为len>=0
这里,以我们的示例一为例来解释
首先,我们的 len 通过计算得知为 2 ,如果len>=0的话,那么
第一次循环 len = 2进入循环
此时head向前,到达2的位置
第二次循环 len=1进入循环
此时head向前,到达3的位置
第三次循环 len=0 进入循环
此时head向前,到达4的位置
我们来验证一下:
一旦我将循环的结束条件写为len>=0那么就会导致头结点多向前走一步,所以我们这里应该为len>0,改正后,我们再来提交一下。
OK,这样就过辣!
第一种方法大家可能很容易想到,但是第二种方法用途非常广泛,使用其的地方也特别多——快慢指针
先来根据一个小学公式:a=2c;
如果这里a代表了链表的总长度,那么c就代表链表长度的一半
链表分为空链表,奇数链表,偶数链表
题目规定,本题没有空链表的出现,所以我们这里只讨论奇数和偶数链表。
首先我们来看奇数链表。
上图,我们分析一下:
当我们的fast指针走到链表的最后一个元素,我们的slow指针刚好落在我们的中间结点上,此时我们的fast就不能再向前了,因为我们的fast的next已经是空了,我们如果还要继续向前的话,就会造成解引用空指针的情况发生,进而导致程序报错。
偶数链表:
当我们的fast指针走到NULL的时候,我们的slow指针刚好落在我们的中间结点上,此时我们的fast就不能再向前了,因为我们的fast已经是空了,我们如果还要继续向前的话,就会造成解引用空指针的情况发生,进而导致程序报错。
下来我们具体的写一下代码:
struct ListNode* middleNode(struct ListNode* head) {ListNode* slow=head;ListNode* fast=head;while(fast&&fast->next){slow=slow->next;fast=fast->next->next;}return slow;
}
我们在这里需要注意的是,我们的循环条件一定是fast&&fast->next
原因:如果我们先判断fast->next,当链表是一个偶数链表的时候fast自身已经为空了,无法解引用,会导致程序报错,所以,我们这里应该首先判断fast为不为空,顺序不能交换。