剑指offer之链表中倒数第k个节点
题目描述:输入一个链表,输出该链表中倒数第k个结点。
问题分析:本题关于对链表的运用。
解一:没看题解之前,我的想法是,先按顺序遍历链表,并将每个节点的数据按顺序存进数组中,最后读取数组中的位置,并构建包括从该位置开始的后面所有数据的一个新链表,返回该节点,则是我们需要得到的节点。但该方法虽然可以实现本题,但显然并不是很好的方法,首先它使用了数组,开辟了新空间,并且在链表的数据节点中的数据较复杂时,这种做法也不适合。具体实现如下:
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
import java.util.ArrayList;
public class Solution {
public ListNode FindKthToTail(ListNode head,int k) {
ArrayList<Integer> list = new ArrayList<>();
ListNode tmp = head;
while(tmp!=null){
list.add(tmp.val);
tmp = tmp.next;
}
ListNode node = null;
if(list.size() >= k && k > 0){//如果k>0这种情况没有考虑到,无法通过
int i = list.size()-k;
node = new ListNode(list.get(list.size()-k));
tmp = node;
while(i < list.size()-1){
i++;
ListNode tmp2 = new ListNode(list.get(i));
tmp.next = tmp2;
tmp = tmp.next;
}
}
return node;
}
}
解二:先遍历一遍链表,计算出结点个数,倒数第k个节点可以转换为顺数第n-k个节点。这种写法明显比上一种要简洁,且不用开辟额外空间,但其实这也并不是这道题想考我们的:
import java.util.ArrayList;
public class Solution {
public ListNode FindKthToTail(ListNode head,int k) {
ListNode tmp = head;
int count = 0;
while(tmp != null){
count++;
tmp = tmp.next;
}
if(k > count || k <= 0)//k的取值应考虑到
return null;
int i = 0;
tmp = head;
while(i < (count-k)){
tmp = tmp.next;
i++;
}
return tmp;
}
}
解三:
快慢指针
将两个指针同时进行平移,具体过程图解释的比较清楚,就不再用文字解释。中心思想,两个指针之间的节点数包含k个,保持前后两个指针相对位置不变向后开始平移,直到后面的指针为最后一个指针结束。这时,前面的指针就是倒数第k’个元素。该方法的时间复杂度只有O(n),只用遍历一遍指针就能得出结果,具体实现如下:
import java.util.ArrayList;
public class Solution {
public ListNode FindKthToTail(ListNode head,int k) {
ListNode fast = head,slow = head;
int i = 0;
//注:首先判断链表为空与数为零的情况
if(head == null)
return null;
if(k == 0)
return null;
while(fast!=null){
i++;
if(i >= k){
break;
}
if(fast.next == null){//此处判断fast是否已经为最后一个指针,若为最后一个指针,且循环还未结束,说明链表节点数小于k,返回null
return null;
}
fast = fast.next;
}
while(fast.next != null){
slow=slow.next;
fast=fast.next;
}
return slow;
}
}