原题目
面试题 02.04. 分割链表
编写程序以 x 为基准分割链表,使得所有小于 x 的节点排在大于或等于 x 的节点之前。如果链表中包含 x,x 只需出现在小于 x 的元素之后(如下所示)。分割元素 x 只需处于“右半部分”即可,其不需要被置于左右两部分之间。
示例:
输入: head = 3->5->8->5->10->2->1, x = 5
输出: 3->1->2->10->5->5->8
第一遍解法
创建一个新链表,遍历两次原链表,第一次遍历将小于x的节点插入,第二次将大于等于x节点插入新链表,最后返回新链表的头指针。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
ListNode *p = head;
ListNode *head2 = new ListNode(0);
ListNode *pre = head2;
ListNode *rail = NULL;
while (p != NULL) {
if (p->val < x) {
rail = new ListNode(p->val);
pre->next = rail;
pre = rail;
rail = rail->next;
}
p = p->next;
}
p = head;
while (p != NULL) {
if (p->val >= x) {
rail = new ListNode(p->val);
pre->next = rail;
pre = rail;
rail = rail->next;
}
p = p->next;
}
return head2->next;
}
};
时间复杂度: O(n)
空间复杂度: O(n)
代码应该还可以进一步优化
- 空间复杂度是否可以O(1) ?
- 代码能否简洁一些?
网上好的解法
双指针,直接在原链表同时遍历和查询。定义头pre和尾tail两个指针。
- 若val < x,则从pre插入链首。
- 若val >= x,则从tail插入链尾。
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
if (head == NULL) { return head; }
ListNode *pre = head;
ListNode *tail = head;
while (head != NULL) {
ListNode *p = head->next;
if (head->val < x) {
head->next = pre;
pre = head;
}
else {
tail->next = head;
tail = head;
}
head = p;
}
tail->next = NULL;
return pre;
}
};
时间复杂度: O(n)
空间复杂度: O(1)
在时间和空间上应该是最优了,但是代码还能简洁一点吗?
最后的代码
没想出来简洁版,就用网上的代码好了。
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
if (head == NULL) { return head; }
ListNode *pre = head;
ListNode *tail = head;
while (head != NULL) {
ListNode *p = head->next;
if (head->val < x) {
head->next = pre;
pre = head;
}
else {
tail->next = head;
tail = head;
}
head = p;
}
tail->next = NULL;
return pre;
}
};
时间复杂度: O(n)
空间复杂度: O(1)
小结
- 无