24. 两两交换链表中的节点
此题我是采用双指针算法做的,这样做不需要在循环中设置临时变量用来存储指针。
具体思路如下:以两个元素为一组,l1位于组内第一个元素之前,l2位于组内第一个元素。
完成一次循环后重新赋值l1和l2。
循环的终止条件为l2不等于null(偶数)
或者l2->next不等于null(奇数)
这里设置虚拟头结点的目的是为了方便处理第一个元素的方向(一般来说要想对链表中的元素进行处理,都要从他的前一个元素入手)
class Solution {
public:
ListNode* swapPairs(ListNode* head)
{
if(head==NULL||head->next==NULL)//先考虑没有元素和只有一个元素的情况
return head;
ListNode*tou=new ListNode(0);//设置虚拟头结点
tou->next=head;
ListNode*l1=tou;
ListNode*l2=tou->next;
while(l2!=NULL&&l2->next!=NULL)
{
l1->next=l2->next;
l2->next=l1->next->next;//上图思路,一步一步变
l1->next->next=l2;
l1=l2;
l2=l1->next;
}
head=tou->next;//找回头结点所在位置
delete tou;//删除虚拟头结点
return head;
}
};
19.删除链表的倒数第N个节点
采用双指针思路,,快指针在正数第n+1位置,慢指针在虚拟头节点位置,快慢同时向前移动,当快指针为null时(到达链表尾),慢指针正好位于需要删除的节点的前一个节点。
证明:设链表共有s个元素,需要删除倒数第n个元素,即为正数第s+1-n个元素
也就是需要遍历到正数第s-n处的元素,当快指针从正数第n+1元素出发走到null时,走了
s-n步,正好可以使慢指针位于s-n处的节点。
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n)
{
ListNode*tou=new ListNode(0);
tou->next=head;
ListNode*l1=tou;
ListNode*l2=tou;
while(n--)
{
l1=l1->next;
}
l1=l1->next;//这里l1要到第n+1个节点
while(l1!=nullptr)
{
l1=l1->next;
l2=l2->next;
}
ListNode*car=l2->next;
l2->next=l2->next->next;
delete car;
head=tou->next;
delete tou;
return head;
}
};
面试题 02.07. 链表相交
思路挺简单的。
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode *h1=headA;
ListNode *h2=headB;
int n1=0;
int n2=0;
while(h1!=NULL)
{
h1=h1->next;
n1++;
}
while(h2!=NULL)
{
h2=h2->next;
n2++;
}
if(n2>n1)
{
swap(n2,n1);
swap(headA,headB);
}
int cha=n1-n2;
h1=headA;
h2=headB;
while(cha--)
{
h1=h1->next;
}
while(h1!=NULL&&h2!=NULL)
{
if(h1==h2)
return h1;
h1=h1->next;
h2=h2->next;
}
return NULL;
}
};
142.环形链表II
这种题具体推导看代码随想录,只在这里记录结论
判断链表是否有环:快慢指针法分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。
如果有环,如何找到这个环的入口:从头结点出发一个指针,从相遇节点(需要上面快慢指针得到的相遇点)也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环形入口的节点。
class Solution {
public:
ListNode *detectCycle(ListNode *head)
{
ListNode*l1=head;
ListNode*l2=head;
while(l2!=NULL&&l2->next!=NULL)//这里因为l2跑的快,所以只需要确定l2的条件即可
//因为用到了l2->next->next,要确保l2!=NULL&&l2->next!=NULL
{
l1=l1->next;
l2=l2->next->next;
if(l1==l2)
{
l1=head;
while(l1!=l2)
{
l1=l1->next;
l2=l2->next;
}
return l1;
}
}
return NULL;
}
};
这里第二个while是嵌套在第一个while里面的,而不是分开写。我的理解是如果第一个while跑完了没得出结果(l1==l2),就可以直接确定不满足有环条件了。要是分开写的话,没有办法在第一个while跑完后就方便的下结论。