链表中倒数第k个结点
一、题目描述
输入一个链表,输出该链表中倒数第k个结点。
二、题目的思路
这道题让我想到了单链表逆置的题目。
思路1
将整个链表进行逆转,要找到第k个结点只需要将新的链表遍历一下就可以了。
思路2
开辟一个足够大的数组,将链表有序的放入数组,要知道倒数第k个结点,在数组中非常简单。但是这个方法在实际应用中不采用,因为内存中很可能有很多无效的结点,全部放入新的数组,非常浪费空间。
思路3
和思路2类似,用栈的方式存储链表的值,再依次弹出k次就是第k个结点。
貌似思路1的思路很好,很完美了,但是问题来了。如果没有给定链表是带头节点的还是不带头节点的,问题就变得麻烦了。两种处理方式有一些差异,那怎么样做到无差异化呢。
思路4
找两个指针都指向第一个结点(不管是头结点还是首结点)然后遍历,遍历时,让第一个指针往后走k-1步,到达第k个结点,这时候开始两个指针一起动。当第一个结点到达末尾时,第二指针所在的位置就是倒数第k个结点。
三、算法实现
3.1、Java实现
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode FindKthToTail(ListNode head,int k) {
if(head==null||k<=0){
return null;
}
ListNode pre=head;
ListNode last=head;
for(int i=1;i<k;i++){
if(pre.next!=null){
pre=pre.next;
}else{
return null;
}
}
while(pre.next!=null){
pre = pre.next;
last=last.next;
}
return last;
}
}
3.2、C++实现版
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
if(pListHead==nullptr||k<=0)return nullptr;
ListNode *pre,*last;
pre=pListHead;
last=pListHead;
for(int i=1;i<k;i++){
if(pre->next==nullptr) return nullptr;
else pre=pre->next;
}
while(pre->next){
pre=pre->next;
last=last->next;
}
return last;
}
};
在解决这里的问题的时候,还发现了一个语法上的问题。pnullptr或者pNULL这样的写法,在C++里,p==nullptr等价于!p,p!=nullptr等价于p,当然这种等价是指布尔属性。
因此改进后的代码如下:
class Solution {
public:
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
if(!pListHead||k<=0)return nullptr;
ListNode *pre,*last;
pre=pListHead;
last=pListHead;
for(int i=1;i<k;i++){
if(!pre->next) return nullptr;
else pre=pre->next;
}
while(pre->next){
pre=pre->next;
last=last->next;
}
return last;
}
};