8道链表常考题-链表划分_初始化


8道链表常考题-链表划分_两个指针_02

LeetCode官方题解

本题要求我们改变链表结构,使得值小于 x的元素,位于值大于等于x元素的前面。这实质上意味着在改变后的链表中有某个点,在该点之前的元素全部小于x ,该点之后的元素全部 大于等于x。 我们将这个点记为JOINT。

8道链表常考题-链表划分_初始化_03


对该问题的逆向工程告诉我们,如果我们在JOINT将改后链表拆分,我们会得到两个更小的链表,其中一个包括全部值小于x的元素,另一个包括全部值大于x的元素。在解法中,我们的主要目的是创建这两个链表,并将它们连接。

双指针法:我们可以用两个指针before 和 after 来追踪上述的两个链表。两个指针可以用于分别创建两个链表,然后将这两个链表连接即可获得所需的链表。

初始化两个指针 before 和 after。在实现中,我们将两个指针初始化为哑 ListNode。这有助于减少条件判断。(不信的话,你可以试着写一个不带哑结点的方法自己看看!)

8道链表常考题-链表划分_初始化_04


利用head指针遍历原链表。

若head 指针指向的元素值 小于 x,该节点应当是 before 链表的一部分。因此我们将其移到 before 中。

8道链表常考题-链表划分_链表_05


否则,该节点应当是after 链表的一部分。因此我们将其移到 after 中。

8道链表常考题-链表划分_链表_06


遍历完原有链表的全部元素之后,我们得到了两个链表 before 和 after。原有链表的元素或者在before 中或者在 after 中,这取决于它们的值。

8道链表常考题-链表划分_两个指针_07


​​注意: 由于我们从左到右遍历了原有链表,故两个链表中元素的相对顺序不会发生变化。另外值得注意的是,在图中我们完好地保留了原有链表。事实上,在算法实现中,我们将节点从原有链表中移除,并将它们添加到别的链表中。我们没有使用任何额外的空间,只是将原有的链表元素进行移动。

现在,可以将 before 和 after 连接,组成所求的链表。

8道链表常考题-链表划分_两个指针_08

为了算法实现更容易,我们使用了哑结点初始化。不能让哑结点成为返回链表中的一部分,因此在组合两个链表时需要向前移动一个节点。

Java

class Solution {
public ListNode partition(ListNode head, int x) {

// before and after are the two pointers used to create the two list
// before_head and after_head are used to save the heads of the two lists.
// All of these are initialized with the dummy nodes created.
ListNode before_head = new ListNode(0);
ListNode before = before_head;
ListNode after_head = new ListNode(0);
ListNode after = after_head;

while (head != null) {

// If the original list node is lesser than the given x,
// assign it to the before list.
if (head.val < x) {
before.next = head;
before = before.next;
} else {
// If the original list node is greater or equal to the given x,
// assign it to the after list.
after.next = head;
after = after.next;
}

// move ahead in the original list
head = head.next;
}

// Last node of "after" list would also be ending node of the reformed list
after.next = null;
// Once all the nodes are correctly assigned to the two lists,
// combine them to form a single list which would be returned.
before.next = after_head.next;

return before_head.next;
}
}

C++实现

8道链表常考题-链表划分_两个指针_09


8道链表常考题-链表划分_初始化_10


8道链表常考题-链表划分_链表_11

我的实现:

/**
* 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 *ltpart = NULL;
ListNode *ltpartend = NULL;
ListNode *btpart = NULL;
ListNode *btpartend = NULL;
if(head == NULL) return NULL;
while(head)
{
if(head->val < x){
//insert(ltpart,head);
if(ltpart == NULL){
ltpart = head;
}else{
ltpartend->next = head;
}
ltpartend = head; //记录尾节点
}else{
//insert(btpart,head);
if(btpart == NULL){
btpart = head;
}else{
btpartend->next = head;
}
btpartend = head;
}

head = head->next;
}
if(ltpartend == NULL){
btpartend->next = NULL;
return btpart;
}else{
ltpartend->next = btpart;
if(btpart != NULL)
{
btpartend->next = NULL;
}
return ltpart;
}
}

};