在算法练习中遇到的链表问题
单链表
1.快慢指针找中点或者某一个位置
class Solution {
public:
bool isPalindrome(ListNode* head) {
ListNode* slow = head, *fast = head, *prev = nullptr;
//快慢指针:使fast指针的前进速度为slow指针的前进速度的两倍,当fast指到链尾时,slow指针就指到链表中间结点
while (fast && fast->next ){//find mid node
slow = slow->next;
fast=fast->next->next;
}
2.链表翻转
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode *p = head;//当前指针节点
ListNode *pre = NULL;//前指针节点
while (p!=NULL) { //循环都将当前节点指向它前面的节点,然后当前节点和前节点后移
ListNode* nxt = p->next;//临时节点,暂存当前节点的下一节点,用于后移
p->next = pre;//将当前节点指向它前面的节点
pre=p;//前指针后移
p=nxt; //当前指针后移
}
return pre;
}
};
3 删除链表中的节点
思路:让要删除的节点的值等于下一个节点的值,删除之后的节点。(因为,我们无法访问我们想要删除的节点 之前 的节点,我们始终不能修改该节点的 next 指针。相反,我们必须将想要删除的节点的值替换为它后面节点中的值,然后删除它之后的节点。*)
class Solution {
public:
void deleteNode(ListNode* node) {
node->val = node->next->val;
node->next = node->next->next; //修改指针语句—— 链表删除
}
};
4.合并链表(1.首尾相连合并链表 2.顺序合并链表)
2.顺序合并链表
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if(l1==NULL)
return l2;
if(l2==NULL)
return l1;
ListNode* pa = l1;
ListNode* pb = l2;
ListNode *l3 = new ListNode(NULL);
ListNode* pc = l3;
while(pa&&pb)
{
if(pa->val <= pb->val)
{
pc->next = pa;
pc=pa;
pa=pa->next;
}
else
{
pc->next = pb;
pc=pb;
pb=pb->next;}
}
pc->next = pa?pa:pb;
return l3->next;
}
};
5.回文链表
思路:
//其一,find mid node 使用快慢指针找到链表中点。
//其二,reverse 逆序后半部分。
//其三,check 从头、中点,开始比较是否相同。
class Solution {
public:
bool isPalindrome(ListNode* head) {
ListNode* slow = head, *fast = head, *prev = nullptr;
//快慢指针:使fast指针的前进速度为slow指针的前进速度的两倍,当fast指到链尾时,slow指针就指到链表中间结点
while (fast && fast->next ){//find mid node
slow = slow->next;
fast=fast->next->next;
}
while (slow){//reverse
ListNode* ovn = slow->next;
slow->next = prev;
prev = slow;
slow = ovn;
}
while (head && prev){//check
if (head->val != prev->val){
return false;
}
head = head->next;
prev = prev->next;
}
return true;
}
};
6.环形链表(链表中是否有环)****
//141.环形链表
//思路:快慢指针,如果慢指针追上快指针则表示有环 返回true 追不上怎表示没环
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode *p = head;
ListNode *q = head;
ListNode * nu = NULL;
while(p && p->next)
{
p = p->next->next;
q = q->next;
if(q == p)
{
return true;
}
}
return false;
}
};
7.找到入环节点
常见的方法是:在确定链表有环之后,慢指针重新指向链表头,快指针留在相遇处;然后快慢指针再以每次移动1个节点的速度前进,最终他们在入环节点相遇。
如图,设整个链表长度为L,环长度为R,且距离具有方向性,例如CB是C点到B点的距离,BC是B点到C点的距离,CB!=BC。当证明有环时,fast和slow都顺时针到了B点,则此时:
slow走的距离:AC+CB
fast走的距离:AC+kR+CB(k=0,1,2…)
由于fast每次走2个节点,slow每次走1个节点,所以:
2(AC+CB) = AC+kR+CB
AC+CB = k*R
AC+CB = (k-1)*R+R
AC = (k-1)*R+R-CB
AC = (k-1)*R+BC
从最终的表达式可以看出来,AC的距离等于绕环若干圈后再加上BC的距离,也就是说慢指针从A点出发以速度1前进、快指针从B点出发以速度1前进,则慢指针到C点时,快指针也必然到了。
function ListNode(x){
this.val = x;
this.next = null;
}
function EntryNodeOfLoop(pHead){
if(pHead === null)
return null;
var fast = pHead;
var slow = pHead;
while(fast.next !==null && fast.next.next !== null) {
slow = slow.next;
fast = fast.next.next;
if(slow === fast)
break;
}
if(fast === null || fast.next === null)
return null;
// 有环,slow重新回到链表头
slow = pHead;
// slow和fast重新相遇时,相遇节点就是入环节点
while(slow !== fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
8、判断两个链表是否相交
两种情况:A;有环
B;没环
A:在环里设置一个指针不动,另一个从头开始移动,指针相遇则相交。
B:判断两个链表最后节点是否相同,相同即相交。
9、 两个链表相交,求交点。
解法1.用两个stack栈
解法2,求出两个链表长度a,b,一个指针从head开始,一个从head+|a-b|开始,相遇即相交。求出交点。