赞
踩
在面试中,链表经常作为简单题出现,虽然题目不难,但是面试者常常会因疏忽实现细节,造成无法短时间内bug-free。
今天小编总结链表常用知识点。点赞收藏,关注公众号[眼罩的程序员笔记],面试前看一遍,快速通关链表题型。
无论当链表中有奇数还是偶数个节点,slow fast 两指针一开始都指向head。慢指针一次走一步,快指针一次走两步。 直至fast 为NULL或者fast->next为NULL时,此时slow 指向中间节点。
循环结束后指针状态见下图。
- ListNode * findMiddle(ListNode * head)
- {
- ListNode * slow = head;
- ListNode * fast = head;
- while(fast!=NULL && fast->next!=NULL)
- {
- slow = slow->next;
- fast = fast->next->next;
- }
- return slow;
- }
不断向后移动相邻的两个指针,翻转两指针间的相邻关系,需注意在翻转之前保存后一个指针的next节点。并且最后把原head的next置为NULL。
如下图红色代表循环第一步,蓝色代表循环第二步。
- ListNode * reverse(ListNode * head)
- {
- if (head==NULL)
- return NULL;
- ListNode * i = head;
- ListNode * j = head->next;
- while(j!=NULL)
- {
- ListNode * tem = j->next;
- j->next = i;
- i= j;
- j=tem;
- }
- head->next = NULL;
- return i;
- }
给定两个链表,要求依次选取其中一个节点,合并两个链表。
下图是一个通用的合并思路,这个思路不仅适用于依次选取节点合并,还适用于将两个有序链表合并为一个有序链表。
首先建立一个dummy 头节点作为合并后链表的dummy头结点,用一个尾指针指向合并后链表的最后一个节点。每次循环将tail 连接到headA,headA 连接到 headB,之后tail 更新为headB。
下图中红线代表循环第一轮,蓝线代表循环第二轮。
- ListNode * merge(ListNode * a, ListNode * b)
- {
- ListNode * dummy = new ListNode(-1);
- ListNode * pre = dummy;
- while(a!=NULL && b!=NULL)
- {
- pre->next = a;
- ListNode * aTem = a->next;
- a->next = b;
- pre=b;
- b=b->next;
- a=aTem;
- }
- if(a!=NULL)
- {
- pre->next= a;
- }
- else if (b!=NULL)
- {
- pre->next =b;
- }
- return dummy->next;
- }
-
题目:给定链表的头结点 head ,请将其按升序排列并返回 排序后的链表 。
链表的特点造成无法方便的交换任意两个任意位置的节点,所以无法使用快排类的排序算法。
而归并排序非常适合链表排序。递归从底到上,相当将长度为1 的子链表排序之后两个合并成长度2的链表;依次递推。
实现过程就用到了上述基础操作中的「快慢指针找中间节点」来把链表一分为二;用「合并链表」将排序好的子链表合并成一个有序的长链表。
1. 给你一个链表的头节点 head ,判断链表中是否有环?
这个题比较简单就是使用快慢指针,慢指针一次走一步,快指针一次走两步,如果快指针在走到结尾之前和慢指针相遇了说明有环,如果没相遇则无环。
2. 如果链表有环,则返回环的起点。
这是上题的follow up, 先明确符号含义:
x: 头结点到 entry红点之间的长度;
y: entry 红点到 meet 红点之间的长度;
m:meet红点 到 entry 红点之间的长度;
R:环的整个长度;
t: t时刻快慢指针在meet点相遇。
假设快慢指针在环内的meet点相遇。
快指针走的距离是慢指针走的距离的两倍,有如下两个等式:
2t = x + n* R + y(快指针);
t = x + y (慢指针)
通过这两个等式可以得到 x = n*R - y; 推出 x = m + (n-1)*R。说明相遇之后将慢指针重新放回起点,快指针后面一次只走一步,两个指针再次相遇的点即为entry 入口点。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。