编程语言
首页 > 编程语言> > 剑指Offer:反转列表(C++)(含完整代码)

剑指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