我一直觉得双指针是一个非常好用的方法,在链表中可以使用,在数组中依然可以,很灵活。
1. 寻找中间结点
用两个指针 slow 与 fast 一起遍历链表。slow 一次走一步, fast 一次走两步。那么当 fast 到达链表的末尾时,slow 必然位于中间。
public ListNode middleNode(ListNode head) {
ListNode slow = head. fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
2. 寻找倒数第K个元素
在这里最重要的思想就是先将fast向后遍历到第k + 1 个结点,slow 仍然指向链表的第一个结点,此时指针fast 与 slow 二者之间刚好间隔 k 个结点。之后两个指针同步向后走,当 fast 走到链表的尾部空节点时,slow 指针刚好指向链表的倒数第K个结点。
这样就很巧妙,主要是思想要理解。
要注意的一点,链表的长度可能小于k,寻找k位置的时候必须判断fast是否为null
public 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. 旋转链表
还是双指针,找到倒数k的位置,也就是两段分割的位置,再将两个链表拼接。
k有可能大于链表长度,所以首先获取一下链表长度len,如果然后k=k % len,如果k == 0,就不用旋转,直接返回头结点。
public ListNode rotateRight(ListNode head, int k) {
if (head == null || k == 0) {
return head;
}
ListNode temp = head;
ListNode slow = head;
ListNode fast = 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;
}