1.寻找中间结点
示例1
输入:[1,2,3,4,5]
输出:此列表中的结点3
示例2:
输入:[1,2,3,4,5,6]
输出:此列表中的结点4
Java代码
public static ListNode middleNode(ListNode head) {
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
对于寻找链表中间结点的问题,我们可以用快慢指针来解决,一个slow指针和一个fast指针一起遍历链表,slow走一步,fast走两步,当fast在处于链表的尾部的时候,slow也就处于中间的位置了。
这里还有一个问题要思考,当链表是偶数的时候,是返回示例2里的3还是4?还有就是通常当数组也是偶数的时候,是返回示例2里的3还是4?为什么会这样?
答案:链表返回4,而数组返回3。
原因:
链表是一种非连续的数据结构,元素通过指针相互连接。在链表中,要查找中间值通常需要遍历链表,采用快慢指针的方式。快指针每次移动两步,慢指针每次移动一步,当快指针到达链表末尾时,慢指针就会指向链表的中间节点。这种算法会导致返回偏后的中间值,因为慢指针在快指针到达末尾之前总是略落后于快指针。
而数组是一个连续的数据结构,每个元素都有一个索引,可以通过索引直接访问。在数组中,中间值通常是位于中间索引的元素。对于包含偶数个元素的数组,有两个中间值,一个位于索引位置 n/2 - 1
,另一个位于索引位置 n/2
,其中 n
是数组的长度。通常情况下,返回偏前的中间值是因为编程语言中的数组索引从0开始计数。
2.寻找倒数第k个元素
我们可以使用快慢指针,让fast先遍历到k+1的结点位置,slow仍然在第一个位置,此时slow和fast就相差了k个结点,此时slow和fast同步走,当fast到达链表的结尾空结点时,slow所指向的就是倒数第k个元素。有个需要注意的问题是链表的长度可能小于k,所以寻找k位置的时候需要判断k位置是否为null。
Java代码
public static ListNode getKthFromEnd(ListNode head, int k) {
ListNode fast = head;
ListNode slow = head;
while (fast != null && k > 0) {
fast = fast.next;
k--;
}
while (fast != null) {
fast = fast.next;
slow = slow.next;
}
return slow;
}
3.旋转链表
Leetcode61.先看题目要求:给你一个链表的头节点head,旋转链表,将链表每个节点向右移动k个位置。
示例1:
输入:head=[1,2,3,4,5],k=2
输出:[4,5,1,2,3]
先用双指针策略找到倒数K的位置,也就是{1,2,3}和{4,5}两个序列,之后再将两个链表拼接
成{4,5,1,2,3}就行了。具体思路是:
因为k有可能大于链表长度,所以首先获取一下链表长度en,如果然后k=k%Ien,如果k==0,则不用
旋转,直接返回头结点。否则:
1.快指针先走k步。
2.慢指针和快指针一起走。
3.快指针走到链表尾部时,慢指针所在位置刚好是要断开的地方。把快指针指向的节点连到原链表头部,慢指针指向的节点断开和下一节点的联系。
4.返回结束时慢指针指向节点的下一节点。
public static ListNode rotateRight(ListNode head, int k) {
if (head == null || k == 0) {
return head;
}
ListNode temp = head;
ListNode fast = head;
ListNode slow = head;
int len = 0;
while (head != null) {
head = head.next;
len++;
}
if (k % len == 0) {
return temp;
}
while ((k % len) > 0) {
k--;
fast = fast.next;
}
while (fast.next != null) {
fast = fast.next;
slow = slow.next;
}
ListNode res = slow.next;
slow.next = null;
fast.next = temp;
return res;
}