目录
24.两两交换链表中的节点(难度:中)
题目链接:力扣
题目描述:给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
类似于昨天的206.反转链表,交替指向。
struct ListNode* swapPairs(struct ListNode* head){
//LNode设置为头节点,并用于返回最终链表
struct ListNode LNode;
LNode.next=head;
struct ListNode* temp=&LNode;
while(temp->next&&temp->next->next){
struct ListNode* left=temp->next;
struct ListNode* right=left->next;
//做对换
temp->next=right;
left->next=right->next;
right->next=left;
//移动指针以进行下一轮替换
temp=left;
}
return LNode.next;
}
19.删除链表的倒数第N个结点
题目链接:力扣
题目描述:给你一个链表,删除链表的倒数第 n
个结点,并且返回链表的头结点。
1.笨办法:求出节点数再做删除
//求节点数
int Size(struct ListNode* head){
struct ListNode* temp=head;
int size=0;
while(temp){
temp=temp->next;
size++;
}
return size;
}
struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
struct ListNode LNode;LNode.next=head; //头节点
struct ListNode* temp=&LNode;
int size=Size(head);
int i=-1;
while(i<size-n-1){
temp=temp->next;
i++;
}
temp->next=temp->next->next;
return LNode.next;
}
2.快慢指针
fast指针比slow指针超前n个结点,当fast遍历到最后一个结点时slow指针刚好指向倒数第N个结点。
必须设置头结点,才能删除倒数第N个元素(也就是第1个元素)。
struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
struct ListNode LNode;LNode.next=head;
struct ListNode* slow=&LNode;
struct ListNode* fast=&LNode;
//快指针向前移动n
for(int i=0;i<n;i++){
fast=fast->next;
}
//快慢指针都动
while(fast&&fast->next){
fast=fast->next;
slow=slow->next;
}
//删除操作
slow->next=slow->next->next;
return LNode.next;
}
面试题 02.07.链表相交(×)
题目链接:力扣
题目描述:给你两个单链表的头节点 headA
和 headB
,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null
。
注意:交点指的是地址相同,并不是单纯的结点内的值相等。
1.算出链表大小做对齐找相同结点
不记得了看讲解:代码随想录。
//返回链表长度
int ListSize(struct ListNode *head){
struct ListNode *temp=head;
int size=0;
while(temp){
size++;
temp=temp->next;
}
return size;
}
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
struct ListNode* longest;
struct ListNode* shortest;
//longest指向较长的链表,shortest指向较短的一个
longest=ListSize(headA)>=ListSize(headB)?headA:headB;
shortest=(longest==headA)?headB:headA;
//dif表示两链表的长度差
int dif=abs(ListSize(headA)-ListSize(headB));
//使两个链表的指针对齐,也就是之后的节点数一样多
while (dif--) {
longest=longest->next;
}
//找到相同的结点
while (longest&&shortest) {
if (longest==shortest) {
return longest;
}
shortest=shortest->next;
longest=longest->next;
}
return NULL;
}
2. 连接链表找入环结点(不能ac)
将第一个链表连到第二个链表之后,如果存在环就转化成了找入环结点的问题,如果不存在环则说明无交点。
但这个题不能ac,因为题目要求不改变链表。
和下面142环形链表是一样的。
142.环形链表II (难度:中)(快慢指针×)
快慢指针
快指针步长为2,慢指针步长为1,如果链表中存在环,那么快慢指针一定会相遇。
我的疑惑
- 无环的情况下如何跳出判断
- 快慢指针相遇说明有环,入环位置怎么确定
(蠢死算了,无环的话快指针肯定要指向NULL了)
总结来说:头结点到入环结点的距离=N*快慢指针相遇结点到入环节点的距离
(数学问题,看讲解,不想看就记住)环形链表讲解
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode *fast=head;
struct ListNode *slow=head;
struct ListNode *temp=head;
struct ListNode *meet=NULL;
//循环中快指针不为空则慢指针就一定不为空
while(fast&&fast->next){
fast=fast->next->next;
slow=slow->next;
//找快慢指针相遇结点
if(fast==slow){
meet=fast;
break;
}
}
//meet为空表示fast在循环过程中指向了空,证明无环
if(meet==NULL){
return NULL;
}
//找入环结点
while(temp!=meet){
temp=temp->next;
meet=meet->next;
}
return temp;
}
代码随想录中的写法(我理解自己的更容易,代码随想录中更简洁):
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode *fast=head;
struct ListNode *slow=head;
struct ListNode *temp=head;
struct ListNode *meet=NULL;
while(fast&&fast->next){
fast=fast->next->next;
slow=slow->next;
if(fast==slow){
meet=fast;
while(temp!=meet){
temp=temp->next;
meet=meet->next;
}
return temp;
}
}
return NULL;
}
明天休息,做回顾和预习!