【剑指Offer-代码的鲁棒性】面试题22:链表中倒数第k个节点

题目描述

输入一个链表,输出该链表中倒数第k个结点(k从1开始)。

思路1

假设链表中共有n个节点,倒数第k个节点即为正数第n-k+1个节点(正数倒数编号都从1开始)。所以我们首先要将链表遍历一遍获得长度n,然后再移动到第n-k+1个节点即可。对应代码如下:

/*
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;
        
        int n = 1;
        ListNode* temp = pListHead;
        while(temp->next!=nullptr){
            temp = temp->next;
            n++;
        }
        if(n<k)
            return nullptr;
        
        ListNode* node = pListHead;
        for(int i=1; i<n-k+1; i++)
            node = node->next;
        return node;
    }
};

思路2

思路1主要的缺点是要先把链表遍历一遍来获取链表的长度。为了解决这个问题,我们可以设置两个指针p1和p2, p1和p2的初始值均为链表头head。首先将p1移动k-1步,此时p1还剩n-k+1步到达链表尾。从第k步开始,p2也开始移动,这样等p1到达链表尾时,p2位于链表第n-k+1个节点,也就是链表倒数第k个节点。

代码如下:

/*
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)  //unsigned int 0-1!=-1,会造成程序崩溃
            return nullptr;
        
        ListNode* p1 = pListHead;
        ListNode* p2 = pListHead;
        for(unsigned int i=0; i<k-1; i++){
            if(p1->next==nullptr)    // k大于链表长度
                return nullptr;
            p1 = p1->next;
        }
        while(p1->next!=nullptr){
            p1 = p1->next;
            p2 = p2->next;
        }
        return p2;
    }
};

注意点

1、链表头pListHead为空;
2、链表节点总数小于k;
3、k是无符号整数,当k=0时,k-1=4294967295,会造成不正确的结果或者程序崩溃。

总结

当链表问题用一个指针不好解决时,可以尝试使用两个指针,让其中一个指针走得快,另一个走得慢。

原文地址:https://www.cnblogs.com/flix/p/12449295.html