面试题15:输入一个链表,输出该链表中倒数第k个结点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾结点是倒数第1个结点。例如一个链表有6个结点,从头结点开始它们的值依次是一、二、三、四、五、6。这个链表的倒数第3个结点是值为4的结点。面试
设置头指针和中间指针,保持相同间隔,朝着同一个方向向前遍历链表。bash
须要注意 k <= 0 的场景和k大于链表长度的场景。oop
public class Solution {
public ListNode FindKthToTail(ListNode head,int k) {
if(k <= 0 || head == null) {
return null;
}
ListNode front = head;
ListNode back = head;
for(int i=0; i< k-1; i++) {
//这里须要经过在纸上画出临界点的场景,好比只有5个节点,求倒数第5个节点和倒数第6个节点的场景
//倒数第5个:k-1 = 4, i 从0~3,总共循环4次,最终遍历到头结点的后序4个节点,即尾节点
//倒数第6个:k-1 = 5, i 从0~4,总共循环5次,最终遍历到出界,若是出现back.next == null,说明出界了
if(back.next == null){
return null;
}
back = back.next;
}
while(back.next != null){
front = front.next;
back = back.next;
}
return front;
}
}
复制代码
若是链表中的总数为奇数,返回中间节点;若是为偶数,返回中间两个节点的任意一个。ui
定义两个指针,同时从链表头结点出发,一个指针一次走一步,另外一个指针一次走两步。spa
当走得快的指针走到链表末尾时,走得慢的指针正好在链表中间。3d
能够在纸上模拟。指针
public static Node findMiddleNode(Node head) {
if (head == null) {
return null;
}
if (head.next == null) {
return head;
}
Node slow = head;
Node fast = head;
//一、当链表有偶数个节点时,能够遍历到倒数第 2 个节点,因为能够返回中间两个节点的任意一个,
// 此时慢指针恰好就是其中两个中间节点的前一个节点,此时定位结束。
//二、当链表有奇数个节点时,能够遍历到最后一个节点,此时慢指针恰好到正中间的节点,定位结束
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
复制代码
定义两个指针,同时从链表头结点出发,一个指针一次走一步,另外一个指针一次走两步。code
若是走得快的指针追上了走得慢的指针,那么链表就存在环形结。cdn
若是走得快的指针走到了链表末尾,即 next 为 null,则代表链表不存在环形结构。blog
能够在纸上模拟。
public static boolean isLoop(Node head) {
if (head == null || head.next == null) {
return false;
}
Node oneStepNode = head;
Node twoStepNode = head;
while (twoStepNode.next != null && twoStepNode.next.next != null) {
oneStepNode = oneStepNode.next;
twoStepNode = twoStepNode.next.next;
//注意避免死循环
if (oneStepNode == twoStepNode) {
return true;
}
}
return false;
}
复制代码