给你一个链表和一个特定值 x ,请你对链表进行分隔,使得所有小于 x 的节点都出现在大于或等于 x 的节点之前。
你应当保留两个分区中每个节点的初始相对位置。
示例:
输入:head = 1->4->3->2->5->2, x = 3
输出:1->2->2->4->3->5
分析
单向链表是一种常用的数据结构,一般会定义个一个值域val和一个指向下一个节点的指针域next,形如:
// Definition for singly-linked list.
struct ListNode {
valueType val;
struct ListNode *next;
}
题目的意图很容易理解,可能会有理解误差的点在于“你应当保留两个分区中每个节点的初始相对位置。”这句话。例如题目中的示例输出为:
1->2->2->4->3->5
而不是
1->2->2->3->4->5
这是因为如果3出现在4之前的话,就破坏了3和4在原始链表中的相对位置(在原始链表中4出现在3之前)。不过也正是由于这句话的存在使得题目的输出结果只有一种,否则的话,符题意的结果就会有很多种.
在不破坏原始元素的相对位置的前提下,只需要诸逐个遍历原始链表中的元素,将小于x的节点和不小于x的节点元素依遍历次序拼接成两个链表,然后组合在一起即可.
实现
struct ListNode* partition(struct ListNode* head, int x){
// 定义一个头节点,其next指针指向小于x的元素组成的链表的header
struct ListNode *lessHeader = malloc(sizeof(struct ListNode));
struct ListNode *lessCurrentHeader = lessHeader;
lessCurrentHeader->next = NULL;
// 定义一个头节点,其next指针指向不小于x的元素组成的链表的header
struct ListNode *moreHeader = malloc(sizeof(struct ListNode));
struct ListNode *moreCurrentHeader = moreHeader;
moreCurrentHeader->next = NULL;
struct ListNode *current = head;
while (current) {
struct ListNode *newNode = current;
// 这里之所以要将current指向原始链表中的下一个位置是因为在if结构中会改变当前current->next值
current = current -> next;
if (newNode->val >= x) {
newNode->next = moreCurrentHeader->next;
moreCurrentHeader->next = newNode;
moreCurrentHeader = moreCurrentHeader->next;
} else {
newNode->next = lessCurrentHeader->next;
lessCurrentHeader->next = newNode;
lessCurrentHeader = lessCurrentHeader->next;
}
}
lessCurrentHeader -> next = moreHeader->next;
return lessHeader->next;
}
算法复杂度
时间复杂度
对于循环来讲,需要循环n(其中n为单链表中节点数)次,而循环体内的操作与n无关,所以时间复杂度为 O ( n ) O(n) O(n);
空间复杂度
整个操作开辟了两个新的头节点来指向新的链表,所以空间复杂度为 O ( 1 ) O(1) O(1)