数据结构之线性表——LeetCode:328. 奇偶链表,86. 分隔链表,24. 两两交换链表中的节点
328. 奇偶链表
题目描述
328. 奇偶链表
给定单链表的头节点 head
,将所有索引为奇数的节点和索引为偶数的节点分别组合在一起,然后返回重新排序的列表。
第一个节点的索引被认为是 奇数 , 第二个节点的索引为 偶数 ,以此类推。
请注意,偶数组和奇数组内部的相对顺序应该与输入时保持一致。
你必须在 O(1)
的额外空间复杂度和 O(n)
的时间复杂度下解决这个问题。
运行代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* oddEvenList(ListNode* head) {
if (head == nullptr) {
return head;
}
ListNode* evenHead = head->next;
ListNode* odd = head;
ListNode* even = evenHead;
while (even != nullptr && even->next != nullptr) {
odd->next = even->next;
odd = odd->next;
even->next = odd->next;
even = even->next;
}
odd->next = evenHead;
return head;
}
};
代码思路
一、整体思路
这段代码的目的是将给定单链表按照节点索引的奇偶性进行分组重新排列。它通过遍历链表,将奇数索引的节点组成一个链表,偶数索引的节点组成另一个链表,最后将偶数链表连接到奇数链表的末尾。
二、函数分析
- 首先检查输入的链表头节点
head
是否为nullptr
,如果是则直接返回head
,表示空链表无需处理。 - 接着,定义一个指针
evenHead
指向链表的第二个节点,因为第二个节点的索引为偶数,这个指针将作为偶数链表的头节点。 - 然后定义两个指针
odd
和even
,分别初始化为head
和evenHead
,用于遍历奇数链表和偶数链表。 - 进入一个循环,循环条件是
even
不为nullptr
且even->next
不为nullptr
。在循环中:even = even->next
:将even
指针移动到下一个偶数节点。even->next = odd->next
:将偶数节点even
的下一个指针指向新的奇数节点的下一个节点,即连接下一个偶数节点。odd = odd->next
:将odd
指针移动到下一个奇数节点。odd->next = even->next
:将奇数节点odd
的下一个指针指向偶数节点even
的下一个节点,即连接下一个奇数节点。
- 循环结束后,奇数链表和偶数链表都已处理完毕。
- 最后,将奇数链表的末尾节点
odd
的下一个指针指向偶数链表的头节点evenHead
,完成链表的重新排列,并返回head
,即重新排列后的链表的头节点。
86. 分隔链表
题目描述
86. 分隔链表
给你一个链表的头节点 head
和一个特定值 x
,请你对链表进行分隔,使得所有 小于 x
的节点都出现在 大于或等于 x
的节点之前。
你应当 保留 两个分区中每个节点的初始相对位置。
运行代码
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
ListNode *smallerDummy = new ListNode(0), *largerDummy = new ListNode(0);
ListNode *smaller = smallerDummy, *larger = largerDummy;
while (head != nullptr) {
if (head->val < x) {
smaller->next = head;
smaller = smaller->next;
} else {
larger->next = head;
larger = larger->next;
}
head = head->next;
}
smaller->next = largerDummy->next;
larger->next = nullptr;
return smallerDummy->next;
}
};
代码思路
一、整体思路
这段代码的目的是将给定链表按照特定值x
进行分隔,使得所有小于x
的节点都出现在大于或等于x
的节点之前,同时保持两个分区中每个节点的初始相对位置。
二、函数分析
- 首先创建两个新的链表头节点
smallerDummy
和largerDummy
,分别用于存储小于x
的节点和大于或等于x
的节点。同时创建两个指针smaller
和larger
,分别初始化为smallerDummy
和largerDummy
,用于遍历和构建这两个新链表。 - 然后进入一个循环,遍历输入链表
head
。在循环中:- 无论当前节点连接到哪个链表,都要将
head
指针更新为head = head->next
,以便继续遍历输入链表。 - 如果当前节点的值大于或等于
x
,则将该节点连接到larger
链表的末尾,即larger->next = head
,然后更新larger
指针为larger = larger->next
。 - 如果当前节点的值小于
x
,则将该节点连接到smaller
链表的末尾,即smaller->next = head
,然后更新smaller
指针为smaller = smaller->next
。
- 无论当前节点连接到哪个链表,都要将
- 循环结束后,输入链表遍历完毕。此时,将
smaller
链表的末尾连接到larger
链表的头部,即smaller->next = largerDummy->next
。然后将larger
链表的末尾设置为nullptr
,以避免形成循环链表。 - 最后,返回
smallerDummy->next
,即分隔后的链表的头节点。
24. 两两交换链表中的节点
题目描述
24. 两两交换链表中的节点
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
运行代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
if(head==nullptr||head->next==nullptr){
return head;
}
ListNode* newhead=head->next;
head->next=swapPairs(newhead->next);
newhead->next=head;
return newhead;
}
};
代码思路
这段代码的目的是实现链表中相邻节点的两两交换。它采用递归的方式,从链表的头部开始,每次交换两个相邻节点,并继续递归处理剩余的链表部分。
- 首先检查输入链表的头节点
head
是否为nullptr
,或者head->next
是否为nullptr
。如果是,说明链表中没有节点或者只有一个节点,无需进行交换操作,直接返回head
。 - 如果链表中有两个或以上的节点,定义一个新的头节点
newhead
为head->next
,表示交换后的链表的新头节点。 - 接着,将
head
节点的下一个节点指向递归调用swapPairs(newhead->next)
的结果,即处理完后面的链表部分后返回的新链表的头节点。这样可以将当前的两个节点与后面交换后的链表连接起来。 - 然后,将
newhead
节点的下一个节点指向head
,完成当前两个节点的交换。 - 最后,返回
newhead
,即交换后的链表的头节点。