当Rust遇上LeetCode #206. 反转链表 [简单]

2020/2/7

题目描述

  • 反转一个单链表。

示例

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

相关标签

链表

解题思路

除了记录链表中的每一个值到Vec中,然后重新生成链表的暴.力法以外(O(2n),O(n))。还有两种更快的方法可以采用,分别是迭代法递归法

  • 迭代法
    在遍历链表时,将当前节点的next指针指向前一个元素,第一个节点的next指针需要指向None。另外还需要一个指针来存储下一个节点。
    - 时间复杂度:O(n),假设n为列表的长度,时间复杂度为O(n)。
    - 空间复杂度:O(1)。

  • 递归法
    假设链表m的长度为n,其中[i+1, n]部分的已经被反转,那么m[i]节点的指针应该指向None,m[i+1]节点(若存在)的指针应当指向m[i]。以此类推,最终可以得到一个完整的反转链表。
    - 时间复杂度:O(n),假设n为列表的长度,时间复杂度为O(n)。
    - 空间复杂度:O(n),由于使用递归,将会使用隐式栈空间,递归深度可能达到n层。

源代码

迭代法

// Definition for singly-linked list.
// #[derive(PartialEq, Eq, Clone, Debug)]
// pub struct ListNode {
//   pub val: i32,
//   pub next: Option<Box<ListNode>>
// }
// 
// impl ListNode {
//   #[inline]
//   fn new(val: i32) -> Self {
//     ListNode {
//       next: None,
//       val
//     }
//   }
// }
impl Solution {
    pub fn reverse_list(head: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
        if(head==None){
            return None;
        }
        // 存放当前节点的next指针指向的节点
        let mut node_p1: Option<Box<ListNode>> = None;
        // 存放下一个节点
        let mut node_p2 = &head;
        while let Some(node) = node_p2{
            node_p1 = Some(Box::new(ListNode {
                                        next: node_p1, 
                                        val: node.val}));
            node_p2 = &node.next;
        }
        node_p1
    }
}
  • 执行用时 :0 ms, 在所有 Rust 提交中击败了100.00%的用户
  • 内存消耗 :2.4 MB, 在所有 Rust 提交中击败了44.00%的用户

递归法

use List::*;
// 链表结构
#[derive(Debug)]
enum List { 
    Cons1(i32, Box<List>), 
    Nil,
}
 
// Methods can be attached to an enum
impl List { 
     #[inline]
    fn new() -> List { 
        Nil
    }
    // 在当前节点前新增节点
    #[inline]
    fn prepend(self, elem: i32) -> List { 
        Cons1(elem, Box::new(self))
    }
     // 获取链表长度
    fn len(&self) -> i32 { 
        match *self { 
            Cons1(_, ref tail) => 1 + tail.len(), 
            Nil => 0
        }
    }
     // 将链表转化为字符串
    fn stringify(&self) -> String {
        match 
*self {
            Cons1(head, ref tail) => {
                format!("{}, {}", head, tail.stringify())
            },
            Nil => {
                format!("Nil")
            },
        }
    }
}
 // 反转链表
fn reverse_list(list:List, acc:List ) -> List{
    match list{
        Cons1(val,tail) => {
            reverse_list(*tail,acc.prepend(val))
        }
        Nil => acc
    }
} 
 
fn main() {   
    let mut head = List::new(); 
    let mut i=0; 
    while i < 10 {
        i+=1;
        head = head.prepend(i);
    }
    println!("{:30}",head.stringify());-
    let result = List::new();
    let result = reverse_list(head,result); 
        println!("{}", result.stringify());
}

在不修改原题目函数签名的情况下难以完成, 目前可以通过采用std::List来实现,另外也可以通过unsafe的裸指针来尝试实现,待续。

总结

Rust由于所有权检查的存在,对于链表的操作相较于别的语言会复杂一些。部分情况下可能需要使用unsafe才能完成。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。