剑指offer:输入一个链表,输出该链表中倒数第k个结点。
思路:由于单项链表不能回头,我思考了两种方法
方法一:先遍历链表,算出链表节点数count,第二次直接遍历到第count-k个节点。但是要注意,可能链表结点数cout小于k,此时要返回NULL。这一条件要先判断。
class Solution {
public:
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
// ListNode temp(0);
int count=0;//count用于统计结点数量
ListNode *temp = pListHead;
while (temp != NULL) //统计节点个数
{
++count;
temp = temp->next;
}
count -= k;
// pListHead = temp;
temp = pListHead;
//注意:要判断要找的节点是否在范围内,如果在范围内,返回节点;如果不在,返回NULL
if(count>=0)
{
while (count--) //从前往后再次搜索
{
temp = temp->next;
}
return temp;
}
else
return NULL;
}
};
方法二
可以用两个指针,一个指针遍历到第k个结点的时候,第二个指针再走到第一个节点,然后两个指针的距离始终保持k-1,这样,当第一个指针的next==NULL,也就是走到最后一个节点的时候,第二个指针对应的位置,就是倒数第k个结点。
这样的好处是能够节省一个循环,时间复杂度会相应降低。从Q(2N) 到Q(N)
注意,但是需要一个小循环让第一个指针先走到第k个指针。同时也存在结点总数小于k的问题,如果循环还没有进行到k次,而第一个指针的已经是NULL,即走到头了,那么,函数返回NULL。
代码如下:可以直接拷贝到IDE上编译运行
//#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <stack>
#include <math.h>
#include <iostream>
using namespace std;
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
class Solution {
public:
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
ListNode *first = pListHead; //第一个指针first
ListNode *second = pListHead; //第二个指针second
int i;
if(first == NULL)
return NULL;
for(i = 1; i <= k; i++){
if(first->next == NULL)
break;如果已经走到头了,就跳出,否则继续走
first = first->next;
}
while(first->next != NULL){//如果第一个指针没有走到头,两个指针想跟着一起走,保持k-1的距离
first = first->next;
second = second->next;
}
return second;
}
};
int main()
{
struct ListNode* p = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* r = (struct ListNode*)malloc(sizeof(struct ListNode));
p->val = 0;
p->next = NULL;
for(int i = 1000; i >= 1; i--){
struct ListNode* t = (struct ListNode*)malloc(sizeof(struct ListNode));//注意,这个空间申请一定要放到for循环内部。
t->val = i;//这种方法是插在头节点p前面,当然也可以插在后面,也可以插在链表的尾部,但是为了方便,需要用一个指针始终指向链表的尾节点
t->next = p->next;
p->next=t;
}
Solution s;
r = s.FindKthToTail(p,1000);
cout << r->val << endl;
system("pause");
return 0;
}