剑指Offer:反转列表(C++)(含完整代码)
作者:互联网
剑指Offer:链表中倒数第k个结点(含完整代码)
题目描述:
输入一个链表,输出该链表中倒数第k个结点。
假设整个链表有n个结点,那么倒数第k个结点就是从头结点开始的第n-k+1个结点。如果我们能够得到链表中的结点个数n,那我们只要从头结点开始往后走n-k+1步就可以了。如何得到结点数n呢?这个不难,只需要从头开始遍历链表,每经过一个结点,计数器加1就行。也就是说我们需要遍历链表两次,第一次统计出链表中结点的个数,第二次就能找到倒数第k个结点。但是面试官期待的解法只需要遍历链表一遍。也就是如下代码。
为了实现只遍历链表一次就能找到倒数第k个结点,我们可以定义两个指针。第一个指针从链表头指针开始遍历向前走k-1,第二个指针保持不动。从第k个指针也开始从链表的头指针开始遍历。由于两个指针的距离适中保持在k-1,当第一个指针也开始(走在前面的)指针到达链表的尾结点时,第二个指针(走在后面的)指针正好是倒数第k个结点。
明白了这个思想后再注意一下代码的鲁棒性,关键的有:头指针为0,返回NULL;k为0,返回NULL;循环过程中如果头指针为NULL,返回NULL;具体原因在下面代码中有注释。
AC代码:
/*
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==NULL||k==0)//输入的pListHead为空指针,由于代码会试图访问空指针指向的内存,程序崩溃
return NULL;
//若k为0,由于k是一个无符号整数,那么在for循环中的k-1就不是-1,而是4294967295(无符号的0xFFFFFFFF)。
//因此for循环的执行次数会远远超出我们的预计,同样也会造成成序崩溃
ListNode *pAhead=pListHead;//pAhead指针先走
ListNode *pBehind=NULL;//pBehind指针后走
for(int i=0; i<k-1; i++) //pAhead指针先走k-1步
{
pAhead=pAhead->next;
if(pAhead==NULL)//若输入的以pListHead为头结点的链表结点总数少于k,由于在for循环中会在链表中向前走k-1步,仍然会由于空指针造成程序崩溃
return NULL;//所以一旦为空,就返回空
}
pBehind=pListHead;//pAhead指针先走k-1步后pAhead和pBhind指针开始一起走
while(pAhead->next!=NULL)
{
pAhead=pAhead->next;
pBehind=pBehind->next;
}
return pBehind;
}
};
技巧:当我们用一个指针遍历链表不能解决问题的时候,可以尝试两个指针来遍历链表。可以先让其中一个指针遍历的速度快一些(比如一次在链表上走两步),或者让它先在链表上走若干步。
完整代码:
#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)
{
if(pListHead==NULL||k==0)//输入的pListHead为空指针,由于代码会试图访问空指针指向的内存,程序崩溃
return NULL;
//若k为0,由于k是一个无符号整数,那么在for循环中的k-1就不是-1,而是4294967295(无符号的0xFFFFFFFF)。
//因此for循环的执行次数会远远超出我们的预计,同样也会造成成序崩溃
ListNode *pAhead=pListHead;//pAhead指针先走
ListNode *pBehind=NULL;//pBehind指针后走
for(int i=0; i<k-1; i++) //pAhead指针先走k-1步
{
pAhead=pAhead->next;
if(pAhead==NULL)//若输入的以pListHead为头结点的链表结点总数少于k,由于在for循环中会在链表中向前走k-1步,仍然会由于空指针造成程序崩溃
return NULL;//所以一旦为空,就返回空
}
pBehind=pListHead;//pAhead指针先走k-1步后pAhead和pBhind指针开始一起走
while(pAhead->next!=NULL)
{
pAhead=pAhead->next;
pBehind=pBehind->next;
}
return pBehind;
}
};
int main()
{
ListNode *one=new ListNode(1);
ListNode *two=new ListNode(2);
ListNode *three=new ListNode(3);
ListNode *four=new ListNode(4);
ListNode *five=new ListNode(5);
one->next=two;
two->next=three;
three->next=four;
four->next=five;
five->next=NULL;
Solution s;
cout<<s.FindKthToTail(one,2)->val<<endl;
return 0;
}
运行结果: 标签:结点,ListNode,Offer,C++,列表,链表,pAhead,NULL,指针
来源: https://blog.csdn.net/qq_40968179/article/details/104589969
永远相信美好