|
| 1 | +/** |
| 2 | + * [148] Sort List |
| 3 | + * |
| 4 | + * Sort a linked list in O(n log n) time using constant space complexity. |
| 5 | + * |
| 6 | + * Example 1: |
| 7 | + * |
| 8 | + * |
| 9 | + * Input: 4->2->1->3 |
| 10 | + * Output: 1->2->3->4 |
| 11 | + * |
| 12 | + * |
| 13 | + * Example 2: |
| 14 | + * |
| 15 | + * |
| 16 | + * Input: -1->5->3->4->0 |
| 17 | + * Output: -1->0->3->4->5 |
| 18 | + * |
| 19 | + */ |
| 20 | +pub struct Solution {} |
| 21 | +use super::util::linked_list::{ListNode, to_list}; |
| 22 | + |
| 23 | +// submission codes start here |
| 24 | + |
| 25 | +/* |
| 26 | + 堆排序需要额外空间, 不行 |
| 27 | +
|
| 28 | + 快排: |
| 29 | + * 不行, 单链表要快排必须同时持有两个 mut 引用, 而 rust 里这是不可能的(不知道用 unsafe 行不行) |
| 30 | + * 不用 rust 的话应该是可行的, Lomuto-partition, 用一个慢指针记录 no_lager_than 位置 |
| 31 | +
|
| 32 | + 归并,有点慢, 每次切分要遍历找到切分点, 而且递归栈深度 O(logN) 也不算严格的 O(1) 空间 |
| 33 | +
|
| 34 | + Rust 标准库的 std::collections::LinkedList 都没有实现 sort() 你敢信... |
| 35 | +
|
| 36 | + 这题用 rust 解对我而言真的是 Hard 级而不是 Medium 级了... |
| 37 | +
|
| 38 | + 这里也是前置知识不足, GG 了解到链表的最佳排序方式确实就是 merge-sort |
| 39 | + */ |
| 40 | +impl Solution { |
| 41 | + pub fn sort_list(mut head: Option<Box<ListNode>>) -> Option<Box<ListNode>> { |
| 42 | + let mut len = 0; |
| 43 | + let mut ptr = head.as_ref(); |
| 44 | + while let Some(node) = ptr { |
| 45 | + len += 1; |
| 46 | + ptr = node.next.as_ref(); |
| 47 | + } |
| 48 | + Solution::merge_sort(head, len) |
| 49 | + } |
| 50 | + |
| 51 | + fn merge_sort(mut head: Option<Box<ListNode>>, len: i32) -> Option<Box<ListNode>> { |
| 52 | + if len < 2 { |
| 53 | + return head; |
| 54 | + } |
| 55 | + let mut next = head.as_mut(); |
| 56 | + let mut i = 1; |
| 57 | + while i < len / 2 { |
| 58 | + next = next.unwrap().next.as_mut(); |
| 59 | + i += 1; |
| 60 | + }; |
| 61 | + let mut l2 = next.unwrap().next.take(); |
| 62 | + let mut l1 = Solution::merge_sort(head, len/2); |
| 63 | + let mut l2 = Solution::merge_sort(l2, len - len/2); |
| 64 | + Solution::merge(l1, l2) |
| 65 | + } |
| 66 | + |
| 67 | + fn merge(mut l1: Option<Box<ListNode>>, mut l2: Option<Box<ListNode>>) -> Option<Box<ListNode>> { |
| 68 | + let mut dummy = Some(Box::new(ListNode::new(0))); |
| 69 | + let mut next = dummy.as_mut(); |
| 70 | + loop { |
| 71 | + match (l1, l2) { |
| 72 | + (Some(mut node1), Some(mut node2)) => { |
| 73 | + let node = if node1.val > node2.val { |
| 74 | + // give back ownership |
| 75 | + l2 = node2.next.take(); l1 = Some(node1); node2 |
| 76 | + } else { |
| 77 | + l1 = node1.next.take(); l2 = Some(node2); node1 |
| 78 | + }; |
| 79 | + next.as_mut().unwrap().next = Some(node); |
| 80 | + next = next.unwrap().next.as_mut(); |
| 81 | + }, |
| 82 | + (Some(mut node1), None) => { |
| 83 | + next.unwrap().next = Some(node1); break |
| 84 | + }, |
| 85 | + (None, Some(mut node2)) => { |
| 86 | + next.unwrap().next = Some(node2); break |
| 87 | + }, |
| 88 | + (None, None) => { break }, |
| 89 | + } |
| 90 | + } |
| 91 | + dummy.unwrap().next |
| 92 | + } |
| 93 | +} |
| 94 | + |
| 95 | +// submission codes end |
| 96 | + |
| 97 | +#[cfg(test)] |
| 98 | +mod tests { |
| 99 | + use super::*; |
| 100 | + |
| 101 | + #[test] |
| 102 | + fn test_148() { |
| 103 | + assert_eq!(Solution::sort_list(linked![4,2,1,3]), linked![1,2,3,4]); |
| 104 | + assert_eq!(Solution::sort_list(linked![-1,5,3,4,0]), linked![-1,0,3,4,5]); |
| 105 | + assert_eq!(Solution::sort_list(linked![]), linked![]); |
| 106 | + } |
| 107 | +} |
0 commit comments