Leetcode 86. 分隔链表

给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。

你应当保留两个分区中每个节点的初始相对位置。

示例:

输入: head = 1->4->3->2->5->2, x = 3

输出: 1->2->2->4->3->5

题目分析:本题让我们把原来的链表进行分隔,小于x的在前,大于等于x的在后。并且,元素之间还需要保持原有的相对顺序。在下面的图例中,我们可以看到原有元素的顺序。分隔完后,在原来索引位置5处的元素2依然排在索引位置为3处的元素2之后。

在思考这道题如何解的时候,我们先回忆一下我们在算法课中也接触过类似的partition方法,这种方法在quick sort(快速排序)中也出现过。快速排序采用分治的思想,通过某一分界值将数组分成左右两部分,将大于等于分界值的数据集中到右侧,将小于分界值的数据集中到左侧。然后分别对左侧右侧进行上述处理,直到每一侧都排好序,那么整体也就排好序了。我们看下面的这个例子,对原数组我们选择最后一个元素作为分界值,然后左侧都是小于70的元素,右侧都是大于70的元素。然后对于左侧和右侧,我们选择他们中的最后一个元素作为分界值继续进行划分,一直到最后每一侧都排好序(即这一侧只含有一个元素或者为空),该算法停止。该算法的时间复杂度为O(nlogn)。

对应的C++参考代码如下

  
  
  1. int partition(vector<int> &input, int low, int high) {

  2. int pivot = input[high];

  3. int i = low - 1;

  4. for (int j = low; j <= high - 1; j++) {

  5. if (input[j] < pivot) {

  6. ++i;

  7. swap(input[i], input[j]);

  8. }

  9. }

  10. swap(input[i + 1], input[high]);

  11. return i + 1;

  12. }

  13. void quickSort(vector<int> &input, int low, int high) {

  14. if (low < high) {

  15. int index = partition(input, low, high);

  16. quickSort(input, 0, index - 1);

  17. quickSort(input, index + 1, high);

  18. }

  19. }

回到本题中,既然需要将链表分隔为两部分,那么我们可以设置两个dummy节点分别保存链表的一部分,dummy1作为小于x的节点的链表的头结点,dummy2作为大于等于x的节点的链表的头结点,如果当前节点的值小于x,我们就将当前节点放到dummy1链表的末尾。如果当前节点的值大于等于x,我们就将其插入dummy2链表的末尾。这样我们就将原链表划分成了两部分,并且保证了相对顺序。最后链接成的链表结果如下图显示,我们的算法时间复杂度为O(n)。下面分别给出不同语言的代码实现。

C++代码

  
  
  1. ListNode* partition(ListNode* head, int x) {

  2. if (head == NULL || head->next == NULL) return head;

  3. ListNode* dummy1 = new ListNode(0);

  4. ListNode* dummy2 = new ListNode(1);

  5. ListNode *tail1 = dummy1, *tail2 = dummy2;

  6. ListNode* curr = head;

  7. while (curr != NULL) {

  8. if (curr->val < x) {

  9. tail1->next = curr;

  10. tail1 = tail1->next;

  11. } else {

  12. tail2->next = curr;

  13. tail2 = tail2->next;

  14. }

  15. curr = curr->next;

  16. }

  17. if (tail1 == NULL) return tail2;

  18. if (tail2 == NULL) return tail1;

  19. tail2->next = NULL;

  20. tail1->next = dummy2->next;

  21. return dummy1->next;

  22. }

Java代码

  
  
  1. public ListNode partition(ListNode head, int x) {

  2. if (head == null || head.next == null) return head;

  3. ListNode dummy1 = new ListNode(0);

  4. ListNode dummy2 = new ListNode(0);

  5. ListNode smallTail = dummy1, largeTail = dummy2;

  6. ListNode curr = head;

  7. while (curr != null) {

  8. if (curr.val < x) {

  9. smallTail.next = curr;

  10. smallTail = smallTail.next;

  11. } else {

  12. largeTail.next = curr;

  13. largeTail = largeTail.next;

  14. }

  15. curr = curr.next;

  16. }

  17. smallTail.next = dummy2.next;

  18. largeTail.next = null;

  19. return dummy1.next;

  20. }

C#代码

  
  
  1. public ListNode Partition(ListNode head, int x) {

  2. if (head == null || head.next == null)

  3. {

  4. return head;

  5. }

  6. ListNode dummy1 = new ListNode(0);

  7. ListNode dummy2 = new ListNode(0);

  8. ListNode smallTail = dummy1, largeTail = dummy2;

  9. ListNode curr = head;

  10. while (curr != null)

  11. {

  12. if (curr.val < x)

  13. {

  14. smallTail.next = curr;

  15. smallTail = smallTail.next;

  16. } else

  17. {

  18. largeTail.next = curr;

  19. largeTail = largeTail.next;

  20. }

  21. curr = curr.next;

  22. }

  23. smallTail.next = dummy2.next;

  24. largeTail.next = null;

  25. return dummy1.next;

  26. }

Golang代码

  
  
  1. func partition(head *ListNode, x int) *ListNode {

  2. if head == nil || head.Next == nil {

  3. return head

  4. }

  5. dummy1 := new(ListNode)

  6. dummy2 := new(ListNode)

  7. smallTail := dummy1

  8. largeTail := dummy2

  9. curr := head

  10. for curr != nil {

  11. if curr.Val < x {

  12. smallTail.Next = curr

  13. smallTail = smallTail.Next

  14. } else {

  15. largeTail.Next = curr

  16. largeTail = largeTail.Next

  17. }

  18. curr = curr.Next

  19. }

  20. smallTail.Next = dummy2.Next

  21. largeTail.Next = nil

  22. return dummy1.Next

  23. }

Python3代码

  
  
  1. def partition(self, head: ListNode, x: int) -> ListNode:

  2. if head == None or head.next == None:

  3. return head

  4. dummy1 = ListNode(0)

  5. dummy2 = ListNode(0)

  6. smallTail = dummy1

  7. largeTail = dummy2

  8. curr = head

  9. while curr != None:

  10. if curr.val < x:

  11. smallTail.next = curr

  12. smallTail = smallTail.next

  13. else:

  14. largeTail.next = curr

  15. largeTail = largeTail.next

  16. curr = curr.next

  17. smallTail.next = dummy2.next

  18. largeTail.next = None

  19. return dummy1.next

由本题可见,一些经典的算法我们还是要学透吃透,这样在碰到类似问题或者问题变种的时候才能将经典算法应用过来,快速解决问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值