题目描述
实现一种算法,找出单向链表中倒数第 k 个节点。返回该节点的值。
题目传输门:添加链接描述
示例:
输入: 1->2->3->4->5 和 k = 2
输出: 4
说明:
- 给定的 k 保证是有效的。
解题思路与代码
-
这道题是一道简单题,考验到了在链表中查找一个指定节点的值的这种普通链表操作。
-
这道题你可以不使用任何技巧也能够做出来,不过更优秀一点的做法就是使用双指针来解决这道题。
方案一: 先遍历链表长度法 (普通做法)
- 倒数第k个节点,就是正数第n - k个节点。我们先遍历出节点的个数,然后再减去k,之后再遍历n - k 个节点 ,就能找到第k个节点的值
具体的代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
//首先while循环,变量出节点的个数,然后再次遍历列表。求值
int kthToLast(ListNode* head, int k) {
int count = 0;
ListNode* pos = head;
while(pos != nullptr){
count++;
pos = pos->next;
}
pos = head;
count -= k ;
while(count > 0){
pos = pos->next;
count--;
}
return pos->val;
}
};
复杂度分析
时间复杂度:
- O(n),因为只是普通的遍历链表
空间复杂度:
- O(1),因为没有用到任何的额外的数据结构
双指针法
-
这种做法比上一种做法更加巧妙。我们先创建两个指针,分别都指向头节点,其中一个指针先走k步,然后再再两个指针一起走。
-
当其中一个指针走到尽头时,另一个指针指向的就是我们所需要的那个节点啦,你仔细想想或者画一下图就能够明白其中的道理。
具体的代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
int kthToLast(ListNode* head, int k) {
ListNode* cur = head;
ListNode* pre = head;
for(int i = 1; i < k; i++)
cur = cur->next;
while(cur->next != nullptr){
cur = cur->next;
pre = pre->next;
}
return pre->val;
}
};
复杂度分析
时间复杂度:
- O(n),虽然表面上这种解法的大O表示法表现出来的时间复杂度与方案一一致,但是还是进行了优化,我们还是少遍历几个节点的。
空间复杂度:
- O(1),因为没有使用额外的数据结构
总结
这道题的主要目的是考察你对链表数据结构的理解以及编程技巧。
- 链表是一种基本的数据结构,在很多编程语言和计算机科学问题中都会出现。熟悉并理解链表是很重要的基础知识。
具体来说,这个问题考察了以下几个方面:
-
链表的理解:你需要了解链表的结构,如何遍历链表,以及如何确定链表的长度。
-
编程技巧:这个问题特别关注你是否可以找到一个高效的解决方案。最直接的方法可能是先遍历整个链表以确定其长度,然后再次遍历来找到倒数第 k 个节点。但是这需要两次遍历。一个更优的解决方案是使用双指针技术,只需要一次遍历即可找到倒数第 k 个节点。
-
边界条件处理:这个问题还需要你处理一些边界条件,比如当链表为空或者 k 大于链表长度时,你的代码应该如何处理。
所以,这个问题的意义主要在于考察你对链表的理解,你的编程技巧,以及你对边界条件的处理能力。
最后的最后,如果你觉得我的这篇文章写的不错的话,请给我一个赞与收藏,关注我,我会继续给大家带来更多更优质的干货内容
。