22 链表中倒数第k个节点(第3章 高质量的代码-代码的鲁棒性)

题目描述:

输入一个链表,输出该链表中倒数第k个结点。

尾节点是倒数第一个节点

测试用例:  

功能测试(第k个节点在中间、是头节点、是尾节点)

特殊输入测试(链表头节点是nullptr指针、链表的头节点个数小于k、k=0)

解题思路:

1)使用两个指针,一个指针先移动k步,如果链表小于k,终止返回nullptr。然后两个指针同时移动,知道后一个指针移出最后一个节点    

//实现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; //不要忘记k<0的情况 无符号不用判断k<0时; ListNode* back = pListHead; //先将指针back移动到第k个元素的位置,索引k的位置 while(back!=nullptr && k>0){ //先判断k=0,然后才是k--。 back=back->next; k--; } if(k>0) //说明链表的长度<k return nullptr; ListNode* front = pListHead; while(back!=nullptr){ //back->next!=nullptr 是错误的。 back=back->next; front=front->next; } return front; } };  

 注:尾节点是倒数第一个节点,因此k=1时,front应该指向尾节点,此时back应该是刚好移出尾节点,为空nullptr。

使用两个指针,一个指针先移动k-1步,如果链表小于k,终止返回nullptr。然后两个指针同时移动,知道后一个指针移动到最后一个节点

//实现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;  //无符号,所以不用判断k<0;
        
        ListNode* back = pListHead;
        //先将指针back移动到第k-1个元素的位置,
        while(back->next!=nullptr && k-1>0){ //为了得知第k个元素是否存在,应该判断back->next!=nullptr而不是back!=nullptr
            back=back->next;
            k--;
        }
        if(k>1) //说明链表的长度<k
            return nullptr;
        
        ListNode* front = pListHead;
        while(back->next!=nullptr){ //back移动到最后一个元素即可
            back=back->next;
            front=front->next;
        }
        
        return front;
    }
};
//实现2
class Solution {
public:
    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        if(pListHead==nullptr || k==0)return nullptr;  //无符号,所以不用判断k<0;
        
        ListNode* back = pListHead;
        //先将指针back移动到第k-1个元素的位置,
        /*while(back->next!=nullptr && k-1>0){ //为了得知第k个元素是否存在,应该判断back->next!=nullptr而不是back!=nullptr
            back=back->next;
            k--;
        }
        if(k>1) //说明链表的长度<k
            return nullptr;*/
        for(unsigned int i=0;i<k-1;++i){
            if(back->next!=nullptr)
                back=back->next;
            else
                return nullptr;
        }
        
        ListNode* front = pListHead;
        while(back->next!=nullptr){ //back移动到最后一个元素即可
            back=back->next;
            front=front->next;
        }
        
        return front;
    }
};

    

对于unsigned int类型要格外注意,在写循环或者判断时,常会遇到对变量--;这种情况要格外注意:

因为当unsigned int k=0; --k后,变量的值并不是-1,而是无符号的0xFFFFFFFF,如果此时判断k>0,还是会成立

//该方法是错误的,当k=0是,K-1为0xFFFFFFFF,back会一直向后访问超出数组
class Solution {
public:
    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        if(pListHead==nullptr || k<0)return nullptr;
        
        ListNode* back = pListHead;
        //先将指针back移动到第k-1个元素的位置
       for(unsigned int i=0; i<k-1; ++i){
            bask=back->next;
        }

        if(k>1) //说明链表的长度<k
            return nullptr;
        
        ListNode* front = pListHead;
        //back移动到最后一个元素
        while(back->next!=nullptr){ //back->next!=nullptr
            back=back->next;
            front=front->next;
        }
        
        return front;
    }
};

  

相似题目:

求链表的中间节点:如果链表中的节点总数为奇数,则返回中间节点;如果链表总数是偶数,则返回中间两个节点的任意一个。

为了解决这个问题,也可以同时定义两个指针,同时从链表出发,一个指针一次走一步,另一个指针一次走两步。当走的快的指针走到链表末尾时,走的慢的指针正好在链表的中间。

猜你喜欢

转载自www.cnblogs.com/GuoXinxin/p/10447460.html