一. 最近老是写题不顺,看来得下点功夫了......
二. 直接参考官方题解......
作者:LeetCode
链接:https://leetcode-cn.com/problems/partition-list/solution/fen-ge-lian-biao-by-leetcode/
1. 看到链表就要想到双指针法或者递归, 果不其然......
2. 双指针法:
直觉: 我们可以用两个指针before
和 after
来追踪上述的两个链表。两个指针可以用于分别创建两个链表,然后将这两个链表连接即可获得所需的链表。
3. 算法: 初始化两个指针 before 和 after。在实现中,我们将两个指针初始化为哑 ListNode。这有助于减少条件判断。(不信的话,你可以试着写一个不带哑结点的方法自己看看!)
4. 利用head
指针遍历原链表。 若head
指针指向的元素值 小于 x
,该节点应当是 before
链表的一部分。因此我们将其移到 before
中。否则,该节点应当是after
链表的一部分。因此我们将其移到 after
中。
5. 遍历完原有链表的全部元素之后,我们得到了两个链表 before
和 after
。原有链表的元素或者在before
中或者在 after
中,这取决于它们的值。
6. 注意: 由于我们从左到右遍历了原有链表,故两个链表中元素的相对顺序不会发生变化。另外值得注意的是,在图中我们完好地保留了原有链表。事实上,在算法实现中,我们将节点从原有链表中移除,并将它们添加到别的链表中。我们没有使用任何额外的空间,只是将原有的链表元素进行移动.
7. 现在,可以将 before
和 after
连接,组成所求的链表。
8. 为了算法实现更容易,我们使用了哑结点初始化。不能让哑结点成为返回链表中的一部分,因此在组合两个链表时需要向前移动一个节点。
9. 特别需要注意的是,倒数第二行after->next = NULL,因为我们的方法不需要额外空间,直接穿针引线,因为after->next受到head影响不一定以NULL结尾,因此一定注意手动结尾.
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
//建立哑节点.
ListNode* before_head = new ListNode(0);
ListNode* after_head = new ListNode(0);
ListNode* before = before_head;
ListNode* after = after_head;
while (head != NULL) {
if (head->val < x) {
before->next = head;
//注意需要移动指针到下一个状态.
before = before->next;
}
if (head->val >= x) {
after->next = head;
//注意需要移动指针到下一个状态.
after = after->next;
}
//注意需要移动指针到下一个状态.
head = head->next;
}
before->next = after_head->next;
after->next = NULL;
return before_head->next;
}
};
复杂度分析
时间复杂度: O(N),其中N是原链表的长度,我们对该链表进行了遍历。
空间复杂度: O(1),我们没有申请任何新空间。值得注意的是,我们只移动了原有的结点,因此没有使用任何额外空间。