复试算法练习Day06
题目描述
输入一个单向链表,输出该链表中倒数第k个结点,链表的倒数第1个结点为链表的尾指针。
链表结点定义如下:
struct ListNode
{
int m_nKey;
ListNode* m_pNext;
};
正常返回倒数第k个结点指针,异常返回空指针.
要求:
(1)正序构建链表;
(2)构建后要忘记链表长度。
数据范围:链表长度满足 1 \le n \le 1000 \1≤n≤1000 , k \le n *k≤n* ,链表中数据满足 0 \le val \le 10000 \0≤val≤10000
本题有多组样例输入。
题目来源
(https://www.nowcoder.com/practice/e45e078701ab4e4cb49393ae30f1bb04?tpId=37&tqId=21235&rp=1&ru=/exam/oj/ta&qru=/exam/oj/ta&sourceUrl=%2Fexam%2Foj%2Fta%3Fpage%3D1%26tpId%3D37%26type%3D37&difficulty=undefined&judgeStatus=undefined&tags=&title=)
输入描述
输入说明
1 输入链表结点个数
2 输入链表的值
3 输入k的值
输出描述
输出一个整数
输入: 8
1 2 3 4 5 6 7 8
4
输出:
5
思路
由于采用单链表,所以不能反向输出倒数第k个节点,所以从头遍历其实效率不高。因此提供两种思路:
思路1:直接从头遍历单链表后得到节点个数n,由于采用的是包含头节点但是头结点无数据元素,因此不将其算为一个节点。之后再次遍历,从头结点的下一个节点开始的第n-k+1个节点即为所求的倒数第k个节点。因此只需向后移动n-k次指针则可以完成题目要求。
思路2:参考王道课后习题最优解,设置两个指针,使其相距为k-1,当后一个指针指向最后一个节点时,前一个指针则指向倒数第k个指针。只需遍历一遍链表即可得到输出结果。
具体实现
//思路1,采用两次遍历链表给出输出结果
LinkNode * FindReverNode(LinkNode* head,int k)
{
if(head==NULL || head->next==NULL)
return NULL;
int NodeCount=0;
//第一个指向即为头指针
LinkNode*fir=head;
//一直往下遍历计数,得出节点个数
while(head->next!=NULL)
{
fir=fir->next;
NodeCount++;
}
if(NodeCount<k)
return NULL;
fir=head->next;
//遍历数组输出在第n-k+1个节点的值即为所求
for(int i=0;i<NodeCount-k;i++)
fir=fir->next;
return fir;
}
//思路2,采用两个指针,使其相距为k-1,后一个指向最后节点的时候,前一个找到所求结果
LinkNode* FindReverNode(LinkNode* head, int k) {
if(head == NULL || head->next==NULL)
return NULL;
//不考虑头结点,即头结点为空
//跳过头结点,指向第一个数据元素
LinkNode *fir = head->next;
LinkNode *sec = head->next;
//将second指针向后移动k-1个距离
for(int i = 1; i < k; i++) {
if(sec->next != NULL)
sec = sec->next;
else {
return NULL;
}
}
//当最后一个指针向后遍历到最后一个节点的时候
//同时第一个指针也向后遍历了k次,
//得到了当前第k个节点的结果,并且输出即可得到结果
while(sec->next != NULL) {
sec = sec->next;
fir= fir->next;
}
return fir;
}
时间复杂度
- 思路1遍历了两次链表。虽时间复杂度是O(n),但如果链表的节点数比较多,比如不能一次将数据读入到内存,遍历后输出将会非常耗时。
- 思路2只遍历了一次链表,时间复杂度是O(n),相比于思路1更加巧妙,不用多次读入数据,提高了算法读写速度。
小结
如果可以反向输出节点,利用reverse函数,如果链表过大可以节省效率,不然由于只能采用单链表,所以从头遍历其实效率一般。第一种思路直接遍历了两次单链表,属于暴力破解,对于单链表如果节点很多,其读写占用时间也很多,第二种思路比较巧妙,采用两个节点相距的距离要求可以同时移动指针,即当后一个节点移动到最后,前一个节点就找到目标节点可以直接输出,需要去理解同时并行的移动指针,思想很巧妙,不容易想到,第一种偏暴力破解,理解起来思路更简单。