个人博客:The Blog Of WaiterXiaoYY 欢迎来互相交流学习。
什么是链表
链表是数据结构的一种,它是一种线性数据结构,与数组相似,但与数组不同,在于它储存数据不一定需要一块完整连续的内存,它的每一个结点除了记录本身的数据之外,还记录着下一个结点的位置(指向下一个结点)。
链表有两种类型:单链表和双链表。
双链表与单链表的不同之处,在于双链表比单链表多了一个指向前一个结点的指针域。
- 链表结构表示
//单链表
struct Node{
ElemType val;
struct Node *next;
}ListNode;
//双链表
struct Node{
ElemType val;
struct Node *next;
struct Node *pre;
}ListNode;
双指针技巧
顾名思义,双指针就是生成两个指针,利用两个指针对链表进行操作,经典问题是判断链表是否有环,相交链表。
- 题目:141.环形链表
给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
示例1:
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。*
示例2:
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。
解题思路
链表有环也就意味着如果一直遍历这个链表,那么是不会停止的,如果用两个指针,一个指针跑得快,一个跑的慢,快的那一个就可以追上前面那一个,当他们相等的时候,就说明该链表有环。
但要注意空链表和链表中只有一个结点的时候,如果只有一个结点,就不是环形链表,返回fasle。
代码
bool hasCycle(struct ListNode *head) {
//空链表时则直接返回false
if(!head)
return false;
//两个指针,且他们都指向链表的头指针
struct ListNode* slow = head;
struct ListNode* fast = head;
//当快指针的下一个和下下个都不为空时,进入循环,这里就可以判断链表只有一个结点的情况
while(fast->next && fast->next->next){
fast = fast->next->next; //快指针走两位
if(fast == slow){
return true;
}
else
slow = slow->next;
}
return false;
}
- 题目:160.相交链表
编写一个程序,找到两个单链表相交的起始节点。
如下面的两个链表:
在节点 c1 开始相交。
示例1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
示例2:
输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null
输入解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
解释:这两个链表不相交,因此返回 null
解题思路
还是采用双指针的做法,但这次却不是快慢指针,而是两个指针同时进行,pA指向headA,pB指向headB,链表短的一方肯定先到达末尾,而到达末尾后,则改变指向长链表的头指针,继续遍历,当长的那方到达末尾后则指向短的一方头指针,如果相交,他们一定会在相交处相遇。
这里借用题解的一份图参考一下
其原理是一个数学差值问题,假设A链表有8个结点,B链表有6个结点,如果在A链表的第5个结点相交,也就是在B链表的第三个结点相交,在走到相交点处时,走的步数是一样的。
当相等的时候,返回即可。
代码
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
//有一个为空链表都返回NULL
if(!headA || !headB)
return NULL;
struct ListNode* pA = headA;
struct ListNode* pB = headB;
while(pA != pB){
pA = pA == NULL?headB : pA->next; //先判断pA是否到达了末尾,如果到了则pA=headB,否则pA指向下一个
pB = pB == NULL?headA : pB->next;
}
return pA;
}
未整理完(2020.3.8)
个人博客:The Blog Of WaiterXiaoYY
欢迎来互相交流学习。