`
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例 1:
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
示例 2:输入:l1 = [], l2 = []
输出:[]
示例 3:输入:l1 = [], l2 = [0]
输出:[0]
思路一:先去一个头
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
if(l1==NULL)
{
return l2;
}
if(l2==NULL)
{
return l1;
}
struct ListNode* head=NULL;
struct ListNode* tail=NULL;
if(l1->val>l2->val)
{
head=tail=l2;
l2=l2->next;
// l1=l1->next;
}
else
{
head=tail=l1;
l1=l1->next;
//l2=l2->next;
}
while(l1!=NULL&&l2!=NULL)
{
if(l1->val>l2->val)
{
tail->next=l2;
l2=l2->next;
}
else
{
tail->next=l1;
l1=l1->next;
}
tail=tail->next;
}
if(l1)
{
tail->next=l1;
}
if(l2)
{
tail->next=l2;
}
return head;
}
给定一个头结点为 head 的非空单链表,返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
示例 1:
输入:[1,2,3,4,5] 输出:此列表中的结点 3 (序列化形式:[3,4,5]) 返回的结点值为 3 。
(测评系统对该结点序列化表述是 [3,4,5])。
注意,我们返回了一个 ListNode 类型的对象 ans,这样: ans.val = 3, ans.next.val = 4,
ans.next.next.val = 5, 以及 ans.next.next.next = NULL.
思路:快慢指针
struct ListNode* middleNode(struct ListNode* head){
struct ListNode* slow=head;
struct ListNode* fast=head;
while(fast&&fast->next)
{
slow=slow->next;
fast=fast->next->next;
}
return slow;
}
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
示例 1:
输入:head = [1,2,3,4,5] 输出:[5,4,3,2,1] 示例 2:
输入:head = [1,2] 输出:[2,1] 示例 3:
输入:head = [] 输出:[]
思路一:反转指针的方向
struct ListNode* reverseList(struct ListNode* head){
if(head==NULL)
{
return head;
}
struct ListNode* n1=NULL;
struct ListNode* n2=head;
struct ListNode* n3=n2->next;
while(n2)
{
n2->next=n1;
n1=n2;
n2=n3;
if(n3)
n3=n3->next;
}
return n1;
}
思路二:头插法:
struct ListNode* reverseList(struct ListNode* head){
struct ListNode* newnode=NULL;
struct ListNode* cur=head;
while(cur)
{
struct ListNode* next=cur->next;
cur->next=newnode;
newnode=cur;
cur=next;
}
return newnode;
}
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。如果链表中存在环 ,则返回 true 。 否则,返回 false 。
示例 1:
输入:head = [3,2,0,-4], pos = 1 输出:true 解释:链表中有一个环,其尾部连接到第二个节点。 示例 2:
输入:head = [1,2], pos = 0 输出:true
解释:链表中有一个环,其尾部连接到第一个节点。 示例 3:
输入:head = [1], pos = -1 输出:false 解释:链表中没有环。
题解:
bool hasCycle(struct ListNode *head) {
struct ListNode *solve=head;
struct ListNode *fast=head;
while(fast&&fast->next)
{
fast=fast->next->next;
solve=solve->next;
if(fast==solve)
{
return true;
}
}
return false;
}
小tips: (1)请证明solve每次走一步,fast每次走两步,那么fast和solve一定会相遇吗?
(2)请证明solve每次走一步,fast每次走三步,那么fast和solve一定会相遇吗?
或者solve每次走一步,fast每次走四步,那么fast和solve一定会相遇吗? 结论:
(1)solve每次走一步,fast每次走两步,那么fast一定会追上solve的 (2)当solve每次走一步,fast每次走三步时:
设solve和fast都进环里面来了,设他们之间的距离为N,每次距离缩减2
即N->N-2->N-4->N-6……
若N为偶数那么最后距离为0即可以相遇
若N为奇数,那么最后结果为-1即fast会在solve前面
设这个环的长度为C
那么他们的新距离就为C-1;
同理
若C-1为偶数那么最后距离为0即可以相遇
若C-1为奇数,那么最后结果为-1即fast会在solve前面,此时会陷入死循环,因为每次快相遇的时候都是fast跑solve前面去了。
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。 如果链表中有某个节点,可以通过连续跟踪
next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0
开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。 不允许修改 链表。
示例 1:输入:head = [3,2,0,-4], pos = 1 输出:返回索引为 1 的链表节点 解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:输入:head = [1,2], pos = 0 输出:返回索引为 0 的链表节点 解释:链表中有一个环,其尾部连接到第一个节点。 示例
3:输入:head = [1], pos = -1 输出:返回 null 解释:链表中没有环。
解题思路: 依旧是使用快慢指针,令slow一次移动移位,fast一次移动两位 则总会在圆环里面一点相遇
设从head到圆环入口距离为L,圆环长C,当两指针相遇时距离圆环入口距离为X
当L够短,C够长时时,当fast刚只走了一圈则有C+X+L=2*(L+X)->C-X=L
这只是特例,若L够长时,那么fast可能已经走了n圈了
此时:nC+X+L=2(L+X)->C-X=L->n*C-X=L->(n-1)*C+C-X=L
即若有两个速度为1的指针分别从head走的指针begin和相遇点走的的指针meet,那么当begin走到入口处时,走了L的距离,此时meet从相遇点绕了n-1圈之后,会到了相遇点,再走C-X的距离就也到了入口处,此时刚好相遇。
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode *slow=head;
struct ListNode *fast=head;
while(fast&&fast->next)
{
fast=fast->next->next;
slow=slow->next;
if(fast==slow)
{
struct ListNode *meet=fast;
struct ListNode *begin=head;
while(begin!=meet)
{
meet=meet->next;
begin=begin->next;
}
return meet;
}
}
return NULL;
}