Skip to content

Commit c68c984

Browse files
authored
Merge pull request #3 from rust-practice/feature/leetcode_support
Add support for leetcode types
2 parents fcca263 + ec402de commit c68c984

File tree

4 files changed

+295
-0
lines changed

4 files changed

+295
-0
lines changed

src/leetcode_env/list.rs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
//! Leetcode Lists Support
2+
3+
use std::fmt::{Debug, Formatter};
4+
5+
#[derive(PartialEq, Eq)]
6+
pub struct ListNode {
7+
pub val: i32,
8+
pub next: Option<Box<ListNode>>,
9+
}
10+
11+
impl Debug for ListNode {
12+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
13+
write!(
14+
f,
15+
"{} -> {}",
16+
self.val,
17+
match self.next.as_ref() {
18+
Some(next) => format!("{next:?}"),
19+
None => "None".to_owned(),
20+
}
21+
)
22+
}
23+
}
24+
25+
impl ListNode {
26+
#[inline]
27+
pub fn new(val: i32) -> Self {
28+
ListNode { next: None, val }
29+
}
30+
}
31+
32+
/// Wrapper class to make handling empty lists easier
33+
#[derive(PartialEq, Eq)]
34+
pub struct ListHead {
35+
head: Option<Box<ListNode>>,
36+
}
37+
38+
impl Debug for ListHead {
39+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
40+
let head: Vec<i32> = self.into();
41+
head.fmt(f)
42+
}
43+
}
44+
45+
impl From<ListHead> for Option<Box<ListNode>> {
46+
fn from(value: ListHead) -> Self {
47+
value.head
48+
}
49+
}
50+
51+
impl From<Option<Box<ListNode>>> for ListHead {
52+
fn from(head: Option<Box<ListNode>>) -> Self {
53+
Self { head }
54+
}
55+
}
56+
57+
impl From<Vec<i32>> for ListHead {
58+
fn from(values: Vec<i32>) -> Self {
59+
// Reverse version before looking at
60+
// https://github.com/zwhitchcox/leetcode/blob/master/src/0002_add_two_numbers.rs
61+
// to see how it could be done going forward instead of backward
62+
//
63+
// let mut last: Option<Box<ListNode>> = None;
64+
// for &n in values.iter().rev() {
65+
// let mut temp = ListNode::new(n);
66+
// temp.next = last;
67+
// last = Some(Box::new(temp));
68+
// }
69+
// ListHead::new(last)
70+
71+
let mut result = Self { head: None };
72+
let mut curr = &mut result.head;
73+
for &num in &values {
74+
let node = ListNode::new(num);
75+
*curr = Some(Box::new(node));
76+
curr = &mut curr.as_mut().unwrap().next;
77+
}
78+
result
79+
}
80+
}
81+
82+
impl From<&ListHead> for Vec<i32> {
83+
fn from(list_head: &ListHead) -> Self {
84+
let mut result = vec![];
85+
let mut curr = &list_head.head;
86+
while let Some(node) = &curr {
87+
result.push(node.val);
88+
curr = &node.next;
89+
}
90+
result
91+
}
92+
}

src/leetcode_env/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
//! Add support for "types" defined on leetcode and methods to facilitate conversion from example format
2+
3+
pub mod list;
4+
pub mod tree;

src/leetcode_env/tree.rs

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
//! Leetcode Tree Support
2+
3+
use std::{
4+
cell::RefCell,
5+
collections::VecDeque,
6+
fmt::{Debug, Formatter},
7+
rc::Rc,
8+
};
9+
10+
#[derive(PartialEq, Eq)]
11+
pub struct TreeNode {
12+
pub val: i32,
13+
pub left: Option<Rc<RefCell<TreeNode>>>,
14+
pub right: Option<Rc<RefCell<TreeNode>>>,
15+
}
16+
17+
impl TreeNode {
18+
#[inline]
19+
pub fn new(val: i32) -> Self {
20+
TreeNode {
21+
val,
22+
left: None,
23+
right: None,
24+
}
25+
}
26+
27+
fn wrapped_node_maybe(val: Option<i32>) -> Option<Rc<RefCell<Self>>> {
28+
val.map(|x| Rc::new(RefCell::new(Self::new(x))))
29+
}
30+
}
31+
32+
// Wrapper class to make handling empty trees easier
33+
#[derive(PartialEq, Eq)]
34+
pub struct TreeRoot {
35+
pub root: Option<Rc<RefCell<TreeNode>>>,
36+
}
37+
38+
impl Debug for TreeRoot {
39+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
40+
let mut vec: Vec<Option<i32>> = self.into();
41+
42+
// Remove trailing None's
43+
while !vec.is_empty() && vec[vec.len() - 1].is_none() {
44+
let _ = vec.remove(vec.len() - 1);
45+
}
46+
47+
let vec: Vec<String> = vec
48+
.iter()
49+
.map(|x| {
50+
if let Some(x) = x {
51+
format!("{x}")
52+
} else {
53+
"None".to_string()
54+
}
55+
})
56+
.collect();
57+
write!(f, "{vec:?}")
58+
}
59+
}
60+
61+
impl From<&TreeRoot> for Vec<Option<i32>> {
62+
fn from(value: &TreeRoot) -> Self {
63+
let mut result = vec![];
64+
let mut deque = VecDeque::new();
65+
if value.root.is_some() {
66+
deque.push_back(value.root.clone());
67+
}
68+
while !deque.is_empty() {
69+
let node = deque.pop_front().unwrap();
70+
match &node {
71+
Some(node) => {
72+
let node = node.as_ref().borrow();
73+
result.push(Some(node.val));
74+
deque.push_back(node.left.clone());
75+
deque.push_back(node.right.clone());
76+
}
77+
None => {
78+
result.push(None);
79+
}
80+
}
81+
}
82+
result
83+
}
84+
}
85+
86+
impl From<Option<Rc<RefCell<TreeNode>>>> for TreeRoot {
87+
fn from(root: Option<Rc<RefCell<TreeNode>>>) -> Self {
88+
Self { root }
89+
}
90+
}
91+
92+
impl From<&str> for TreeRoot {
93+
/// Expects the "[]" around the values, separated by comma "," and only integers and "null"
94+
/// (which is the format you'll get on LeetCode)
95+
///
96+
/// # Panics
97+
///
98+
/// This function panics if it doesn't match the expected format
99+
fn from(value: &str) -> Self {
100+
let mut result: Vec<Option<i32>>;
101+
// Check and remove "[]"
102+
assert!(value.len() >= 2);
103+
assert_eq!('[', value.chars().next().unwrap());
104+
assert_eq!(']', value.chars().nth(value.len() - 1).unwrap());
105+
if value.len() == 2 {
106+
// Empty array return empty tree
107+
return Self { root: None };
108+
}
109+
let value = &value[1..value.len() - 1];
110+
111+
// Separate by comma
112+
let values: Vec<&str> = value.split(',').map(|v| v.trim()).collect();
113+
114+
// Convert into values
115+
result = vec![];
116+
for value in values {
117+
result.push(if value == "null" {
118+
None
119+
} else {
120+
Some(value.parse().unwrap())
121+
})
122+
}
123+
124+
result.into()
125+
}
126+
}
127+
128+
impl Debug for TreeNode {
129+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
130+
let left = if let Some(left) = &self.left {
131+
format!("{:?}", left.as_ref().borrow())
132+
} else {
133+
"None".to_string()
134+
};
135+
let right = if let Some(right) = &self.right {
136+
format!("{:?}", right.as_ref().borrow())
137+
} else {
138+
"None".to_string()
139+
};
140+
write!(f, "{{val:{} left:{} right:{}}}", self.val, left, right)
141+
}
142+
}
143+
144+
impl From<Vec<i32>> for TreeRoot {
145+
fn from(value: Vec<i32>) -> Self {
146+
value
147+
.iter()
148+
.map(|x| Some(*x))
149+
.collect::<Vec<Option<i32>>>()
150+
.into()
151+
}
152+
}
153+
154+
impl From<Vec<Option<i32>>> for TreeRoot {
155+
/// Converts the incoming vec into a tree
156+
fn from(list: Vec<Option<i32>>) -> Self {
157+
// Based on https://leetcode.com/problems/recover-binary-search-tree/solutions/32539/Tree-Deserializer-and-Visualizer-for-Python/
158+
159+
if list.is_empty() {
160+
return TreeRoot { root: None };
161+
}
162+
163+
let nodes: Vec<Option<Rc<RefCell<TreeNode>>>> = list
164+
.iter()
165+
.map(|x| TreeNode::wrapped_node_maybe(*x))
166+
.collect();
167+
168+
let mut kids: Vec<Option<Rc<RefCell<TreeNode>>>> = nodes
169+
.iter()
170+
.rev()
171+
.map(|x| x.as_ref().map(Rc::clone))
172+
.collect();
173+
174+
let root = kids.pop().expect("Check for empty done at top");
175+
176+
for node in nodes.into_iter().flatten() {
177+
if let Some(left_child) = kids.pop() {
178+
node.borrow_mut().left = left_child;
179+
}
180+
if let Some(right_child) = kids.pop() {
181+
node.borrow_mut().right = right_child;
182+
}
183+
}
184+
185+
TreeRoot { root }
186+
}
187+
}
188+
189+
impl From<TreeRoot> for Option<Rc<RefCell<TreeNode>>> {
190+
fn from(value: TreeRoot) -> Self {
191+
value.root
192+
}
193+
}

src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
mod leetcode_env;
2+
3+
pub use leetcode_env::list::ListHead;
4+
pub use leetcode_env::list::ListNode;
5+
pub use leetcode_env::tree::TreeNode;
6+
pub use leetcode_env::tree::TreeRoot;

0 commit comments

Comments
 (0)