【问题标题】:Reordering a linked list efficiently有效地重新排序链表
【发布时间】:2015-08-05 11:56:16
【问题描述】:

我在一次采访中得到了这个问题,如下:

如果我有这样的链表,

1->2->3->4->5->6

我必须把它转换成,

1->6->2->5->3->4

如果是这样的话,

1->2->3->4->5->6->7

我必须把它转换成

1->7->2->6->3->5->4

而且,最重要的是,我必须修改原来的链表,我不能创建一个新的链表。我想到了一个递归。但是,我无法真正解决它。而且,它们是一个约束,这个函数只能有链表的头部。

【问题讨论】:

  • @John Lui 有时迭代解决方案更简单。

标签: algorithm linked-list


【解决方案1】:

这可以在线性时间O(n) 内完成,而且通常在面试中(不幸的是)比解决方案的稳健性更重要。

您可以通过将原始列表分成两个(尽可能)大小(尽可能)的列表,然后反转第二个并逐个元素合并它们(第一个列表中的第一个元素,第二个列表中的第二个元素ETC)。您不需要太多额外的空间,因为您可以使用现有的指针。

例如:

1->2->3->4->5->6

1->2->3 and 4->5->6 // after split, 3 points to null, 4 is head of second list
1->2->3 and 4<-5<-6 // after reorder
1->6->2->3 and 4<-5 // first phase of merge
1->6->2->5->3 and 4 // second phase of merge
1->6->2->5->3->4    // last phase of merge

您可以使用running pointer 找到分割点。遍历列表时,一个指针一次指向一个节点,一个指针一次指向两个节点。当较快的指针到达末尾(null)时,较慢的指针将在拆分之前,拆分之前的节点必须指向 null 而不是下一个节点(在我们的例子中是 4)和下一个节点(4)成为第二个列表的头部。

反转第二个列表并合并是简单的指针交换。

注意空指针:-)

【讨论】:

    【解决方案2】:

    这可以使用递归算法来完成。您需要以“螺旋”方式(first-last-first-last)遍历列表。所以,我的想法是分离列表的第一个和最后一个元素,连接它们并递归地对其余元素执行相同的操作。

    以下是算法的大致轮廓:

    modifyList(head):
        if head.next == null or head.next.next == null: # when the list contains 1 or 2 elements, keep it unchanged
            return head
    
        nextHead = head.next # head of the list after removing head and last item
        last = head.next
        beforeLast = head
        while last.next != null: # find the last item, and the item before it
            beforeLast = last
            last = last.next
    
        head.next = last # append last item after first
        beforeLast.next = null # remove the last item from list
        last.next = modifyList(nextHead) # recursively modify the 'middle' elements and append to the previous last item
        return head
    

    【讨论】:

    • 值得考虑这是在 n^2 次​​span>
    【解决方案3】:

    这是一种递归方式。

    创建一个函数nreverse 来反转一个链表。 Common Lisp 有这个功能。

    盯着列表的头部,如果列表长于一个元素,nreverse第一个元素之后的列表。在方案中:

    (setcdr listx (nreverse (cdr listx)))
    

    递归到列表的下一个子列表。这是 Common Lisp 中的全部内容:

    ? (defun munge (listx)
      (let ((balx (cdr listx)))
        (if (null balx)
            listx
            (progn (rplacd listx (nreverse balx))
                   (munge (cdr listx))
                   listx))))
    MUNGE
    ? (munge '(1 2 3))
    (1 3 2)
    ? (munge '(1 2 3 4 5 6))
    (1 6 2 5 3 4)
    ? (munge '(1 2 3 4 5 6 7))
    (1 7 2 6 3 5 4)
    ? 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-12-06
      • 2019-10-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多