caibirdme / leetcode_rust

practice rust by solving leetcode problems
MIT License
5 stars 0 forks source link

linked-list #2

Open caibirdme opened 4 years ago

caibirdme commented 4 years ago

go over linked-list related problems

caibirdme commented 4 years ago

Convert Sorted List to Binary Search Tree 把一个有序链表转成平衡二叉搜索树。想想一下,如果我们已经有了这颗BST,那么我们对它进行中序遍历,结果就是题目给的链表。我们可以尝试遍历这颗虚拟的树。回想一下怎么在0..n初始化一颗线段树,同样的做法。只是我们使用中序遍历。

    fn in_order(head: &mut Option<Box<ListNode>>, l: usize, r: usize) -> Option<Rc<RefCell<TreeNode>>> {
        if l == r {
            let node = TreeNode::new(head.as_ref().unwrap().val);
            *head = head.take().unwrap().next;
            return Some(Rc::new(RefCell::new(node)));
        }
        let mid = (l+r) / 2;
        let lch = {
            if mid > l {
                Self::in_order(head, l, mid-1)
            } else {
                None
            }
        };
        let mut root = TreeNode::new(head.as_ref().unwrap().val);
        *head = head.take().unwrap().next;
        root.left = lch;
        root.right = Self::in_order(head, mid+1, r);
        Some(Rc::new(RefCell::new(root)))
    }
caibirdme commented 4 years ago

Copy List with Random Pointer 复制单链表很容易,但是由于链表除了next还有个random域,因此复制时需要新建两个节点。并且由于random会随机指向,random可能指向自己,也可能多个random指向同一个节点。因此最直观的办法就是,我们需要建立一个原始链表节点和新链表节点的映射关系。如果random指向的节点已经新建过,就直接指过去。新老关系用hash即可。

还有一种更简便的方式。我们可以把新节点放到原始链表节点的后面,构成这样一个链表。

old1 -> old2 -> old3 -> ...
new1 -> new2-> new3 -> ...

---------
old1 -> new1 -> old2 -> new2 -> ...

之前我们通过hashmap来建立旧节点和新节点的映射关系,而现在,我们直接利用位置来建立映射关系。对于纠结点x,它对应的新节点x'就是x->next。当我们建立完这个链表之后,对于在复制random指针时,x->next->random = x->random->next 这个方法非常巧妙,需要仔细体会。它的启示就是,建立映射处理通过hash直接映射,还可以通过位置进行映射,或者其他方式,可以根据题意来思考。

caibirdme commented 4 years ago

小节: 链表题目主要还是属于基本功, 基本上不太可能有hard的链表题. 单链表的特点是无法倒序遍历和索引,只能顺序遍历,因此题目大多围绕这两个点展开:

链表的另一类问题就是和环相关: