链表中倒数第k个节点 栈 双指针 扩展:寻找链表的中间节点

传送门

分析:

       首先,这道题考察了程序的鲁棒性,主要是关于空指针以及k的取值问题

       第一种思路:可以使用一个栈来实现,由于栈是后进先出的一种数据结构,我们可以将遍历链表的节点存储到栈中,接着弹栈k次即可得到倒数第k个节点。

       第二种思路:双指针

              我们考虑设置两个指针,开始时都指向头结点,第一个指针向前移动k-1次,这样它就到达了第k个节点,第二个指针指向头结点,它们相距k-1步,接着同时移动两个指针,直至第一个指针指向尾节点,这样第二个指针就指向倒数第k个节点。

栈:

//可以把链表放到栈中,然后逆向弹出第k个元素即为倒数第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) return nullptr;
        stack<ListNode*>solve;
        while(!solve.empty()) solve.pop();
        ListNode* pNode = new ListNode(-1);
        pNode = pListHead;
        while(pNode!=nullptr)
        {
            solve.push(pNode);
            pNode = pNode->next;
        }
        ListNode* num = new ListNode(-1);
        if(k>solve.size()||k==0) return nullptr;
        while(k--)
        {
            num = solve.top();
            solve.pop();
        }
        return num;
    }
};

双指针:

//第一种思路:是使用一个栈来储存链表从前向后遍历的节点,然后经历k次弹栈即可
//第二种思路:使用双指针,设置两个指针,首先都指向头结点,接着第一个指针向前移动k步
//那么第二个指针与第一个指针相差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;
        ListNode* First = pListHead;
        ListNode* Second = pListHead;
        for(int i=0;i<k-1;i++)
        {
            First = First->next;
            if(First==nullptr) return nullptr;
        }
        while(First->next!=nullptr)
        {
            First = First->next;
            Second = Second->next;
        }
        return Second;
    }
};

扩展:寻找链表的中间节点

分析:我们可以定义两个指针,同时从链表的头结点出发,一个指针一次走一步,另一个指针一次走两步,当走得快的指针走到链表的末尾时,走得慢的指针正好在链表的中间。

当我们用一个指针遍历链表不能解决问题的时候,可以尝试用两个指针来遍历链表。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章