题目描述
输入一个链表,输出该链表中倒数第k个结点。
思路:
倒着数,关联着先进后出的栈。在这里可以采用栈来做,把所有的节点指针进栈,然后再弹出(k-1)个数,现在的栈顶即为所求节点。
时间复杂度O(n),两次遍历
空间复杂度O(n),辅助内存存储全部数据
代码如下:
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
//栈底层采用的是deque的实现方式,比较复杂,所以这里指定使用轻量级的vector来作为底层实现
//有疑惑的可以查看《STL源码剖析》
stack<ListNode*, vector<ListNode*>> s;
if (pListHead == NULL || k == 0) {//这里的k是unsigned int类型,所以不会是负数
return NULL;
}
while (pListHead) {
s.push(pListHead);
pListHead = pListHead->next;
}
if (s.size() < k) {
return NULL;
} else {
for (int i = 1; i < k; i++) {//这里尽量不要采用k递减的方式,容易出错
s.pop();
}
}
return s.top();//栈定义于函数内部,当函数执行完毕,局部变量内存会被回收,无需考虑内存问题
}
};
1.定义两个指针preNode和currNode,两个指针之间相差k,即currNode-preNode = k(我这只是这么写你们看着方便而已,实际上这样是不对的,因为只有RandomAccessIterator才有这种功能。参考C++ Primer 5th P365)。
2.两个指针同时递增,即它们之间的距离始终相差k。
3.结束条件:currNode 为 NULL,此时的 preNode 即为所求
时间复杂度O(n),接近两次遍历
空间复杂度O(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 (k == 0 || pListHead == NULL) {
return NULL;
}
ListNode* currNode = pListHead;
//currNode节点向前移动 K 个位置
for (int i = 0; i < k; i++) {
if (currNode == NULL) {
return NULL;
}
currNode = currNode->next;
}
while(currNode != NULL) {
pListHead = pListHead->next;
currNode = currNode->next;
}
return pListHead;
}
};
大神代码:
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
ListNode* currNode = pListHead;
int i = 0;
//考虑用一个循环来做
for (; currNode != NULL; i++) {
if (i >= k) {
pListHead = pListHead->next;
}
currNode = currNode->next;
}
return i < k ? NULL : pListHead;
}
};