Leetcode 第19题 - 删除链表的倒数第N个节点(easy)

给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。

示例:

给定一个链表: 1->2->3->4->5, 和 n = 2.

当删除了倒数第二个节点后,链表变为 1->2->3->5.

说明:

给定的 n 保证是有效的。

进阶:

你能尝试使用一趟扫描实现吗?

解题思路

这道题的难点是怎么找到倒数 第 n个节点,就好像 你如果不把每一颗盒子里面的糖都吃一遍,那么 你就没法确切的知道 有多少颗 酸的多少颗是甜的。 我们要知道 倒数第n个数 那必须要知道 最后一个数,才能相对的确定第 倒数第 n 个数。

那么 一种可行方法是 先遍历一遍链表 计算出链表有多少个值,然后可以确定 最后第 n个数的位置 其中一种方案 是 我们递归调用 然后从后向前回溯,就能找到 这也是 rust 里面相对便于实现的一种方法。

在rust 里面 操作链表 比较麻烦,我们 通常用 take() 来吧当前链表 拿到手,take 会把 当前链表的 替换为为nil 然后我们就能获取链表的所有权了。

递归栈 回溯

我们 先递归到底,然后到底之后给定的 n 就可以 减去 1,这样 从底部开始 减,那么 减到 第 n 个就是 0了,然后 我们 直接返回向上返回 它的 next 而不返回当前节点,这样就可以实现删除啦。

要对 n 操作 所以我们单独写一个函数,把 n 改成引用类型。

use std::borrow::BorrowMut;
impl Solution {
    pub fn remove_nth_from_end(head: Option<Box<ListNode>>, n: i32) -> Option<Box<ListNode>> {
        let mut n = n;
        Solution::remove_nth_from_end_recursion(head,n.borrow_mut())
    }
    pub fn remove_nth_from_end_recursion(head: Option<Box<ListNode>>, n: &mut i32   ) -> Option<Box<ListNode>> {
        let mut linlist: Option<Box<ListNode>>  = head;
        match linlist.take() {
            None => {None},
            Some(mut x) => {
            		// 递归栈
                let next = Solution::remove_nth_from_end_recursion(x.next.take(),n);
                //上面 会递归到底 然后我们在这每次-1 来计算倒数n个
                *n -=1;
                println!("{}",*n);
                //如果 当前节点是倒数第 n 个,那么 我们 返回这个节点的next 节点 跳过当前节点,相当于删除了当前节点
                if *n == 0 {
                    return next	;
                }else{
                //否则一般情况 把 next 和 当前节点 链接在一起返回
                    x.next = next;
                    return Some(x);
                }
            },

        }

    }

}

image-20200701233310512