Skip to content

Commit 6dc3378

Browse files
committed
solve #100
1 parent a09d379 commit 6dc3378

5 files changed

+223
-0
lines changed

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ Run `cargo run {id}` to initialize the template submission file of "question #id
44

55
Run `cargo test test_{id}` to test the solution for "question #id".
66

7+
对于大部分难度为 Hard 的问题, 会有中文的思路注释
8+
79
Working in progress, to do:
810

911
- [ ] auto generation of solution list (when 100 problems solved)
@@ -13,3 +15,4 @@ Working in progress, to do:
1315
* Remove all the solution .rs
1416
* Clean lib.rs file
1517
* Start your leetcode journey in rust by typing `cargo run {question_id}`
18+

src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,5 @@ mod n0095_unique_binary_search_trees_ii;
9999
mod n0096_unique_binary_search_trees;
100100
mod n0097_interleaving_string;
101101
mod n0098_validate_binary_search_tree;
102+
mod n0099_recover_binary_search_tree;
103+
mod n0100_same_tree;

src/n0097_interleaving_string.rs

+12
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,18 @@ pub struct Solution {}
2323
// submission codes start here
2424

2525
// DFS with memorization
26+
/*
27+
思路: DFS, 三个指针 i,j,k 分别指向 s1, s2, s3 已经消费到的 char 位置, 下一个可以走的路径是 s3 当前消费到的 char 值
28+
29+
如 aaaaaas aaaaaaaw aaaaaaaaaaaaaasw
30+
那么第一步可以从 s1 或 s2 取一个 char, 用 DFS 的方式搜索整个解空间
31+
32+
优化: 直接 DFS 非常慢, 还是上面的例子, 最差情况是大量重复字符, 时间复杂度直接是 2^(M+N), 优化方式借鉴 DP 经常用到的
33+
memorize, 使用一个二维数组缓存每一对遍历过的 i,j 最后是否能产生合法的 interleaving.
34+
35+
优化后通过缓存剪除的路径比较难分析, 但很显然能知道最差情况也只需要将所有 M*N 的组合进行标记, 因此最差时间复杂度 O(M*N)
36+
空间复杂度 O(M*N)
37+
*/
2638

2739
impl Solution {
2840
pub fn is_interleave(s1: String, s2: String, s3: String) -> bool {
+139
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/**
2+
* [99] Recover Binary Search Tree
3+
*
4+
* Two elements of a binary search tree (BST) are swapped by mistake.
5+
*
6+
* Recover the tree without changing its structure.
7+
*
8+
* Example 1:
9+
*
10+
*
11+
* Input: [1,3,null,null,2]
12+
*
13+
* 1
14+
* /
15+
* 3
16+
* \
17+
* 2
18+
*
19+
* Output: [3,1,null,null,2]
20+
*
21+
* 3
22+
* /
23+
* 1
24+
* \
25+
* 2
26+
*
27+
*
28+
* Example 2:
29+
*
30+
*
31+
* Input: [3,1,4,null,null,2]
32+
*
33+
* 3
34+
* / \
35+
* 1 4
36+
* /
37+
* 2
38+
*
39+
* Output: [2,1,4,null,null,3]
40+
*
41+
* 2
42+
* / \
43+
* 1 4
44+
* /
45+
* 3
46+
*
47+
*
48+
* Follow up:
49+
*
50+
*
51+
* A solution using O(n) space is pretty straight forward.
52+
* Could you devise a constant space solution?
53+
*
54+
*
55+
*/
56+
pub struct Solution {}
57+
58+
use super::util::tree::{TreeNode, to_tree};
59+
60+
// submission codes start here
61+
62+
/*
63+
基本思路: 对 root, 收集左右两侧的节点值:
64+
65+
- 右侧有值小于 root, 左侧有值大于 root: 交换这两个值
66+
- 一侧有值不合法, 另一侧合法: 交换不合法的值与 root
67+
- 两侧都合法: 递归对左右子树进行上述操作
68+
69+
直接使用上述思路会重复迭代子树, 因此可以先用一次中序遍历, 将值的分布记录在数组中, 之后可以用 O(1) 的时间得到某个 node 两侧的值分布
70+
71+
这种办法的时间空间复杂度都是 O(N)
72+
73+
原题中的 follow up 部分提出可以想一个常数空间复杂度的算法, 因此可以继续优化.
74+
75+
最开始的办法会重复迭代子树是因为 Top-down, 可以尝试一下 Bottom-up 能不能解决问题:
76+
77+
- 后序遍历递归校验每个 node 是否合法
78+
- 假如 node 合法, 那么只需要把这个子树中的最大值和最小值返回到上一个层级来帮助判断上一个层级的子树是否合法即可, 无需记录这个子树的所有值
79+
- 假如 node 不合法, 按最开始的办法进行处理, 除非...
80+
- 只有一侧值不合法, 这时候由于是 Bottom-up, 不能直接交换不合法的值与 root, 而要判断交换后能否合法(Top-down 的办法中由于题目给定了有且仅有 swap 一次, 因此与 root 交换必然是合法的)
81+
82+
这个办法时间复杂度 O(N), 空间 O(1). 题解就用 Bottom-up 来写.
83+
*/
84+
use std::rc::Rc;
85+
use std::cell::RefCell;
86+
impl Solution {
87+
pub fn recover_tree(root: &mut Option<Rc<RefCell<TreeNode>>>) {
88+
Solution::recover_helper(root.as_ref());
89+
}
90+
91+
fn recover_helper(root: Option<&Rc<RefCell<TreeNode>>>)
92+
-> (Option<Rc<RefCell<TreeNode>>>, Option<Rc<RefCell<TreeNode>>>, bool) {
93+
if let Some(node) = root {
94+
let (l_min, l_max, l_flag) = Solution::recover_helper(node.borrow().left.as_ref());
95+
let (r_min, r_max, r_flag) = Solution::recover_helper(node.borrow().right.as_ref());
96+
// we've already find a swap, return quickly
97+
if l_flag || r_flag {
98+
return (None, None, true);
99+
}
100+
let root_val = node.borrow().val;
101+
let l_err = l_max.as_ref().map_or(false, |v| v.borrow().val > root_val);
102+
let r_err = r_min.as_ref().map_or(false, |v| v.borrow().val < root_val);
103+
// invalid sub-tree found, do swap
104+
if l_err || r_err {
105+
if l_err && r_err {
106+
107+
} else if l_err {
108+
std::mem::swap(&mut l_max.unwrap().borrow_mut().val, &mut node.borrow_mut().val);
109+
} else if r_err {
110+
std::mem::swap(&mut r_min.unwrap().borrow_mut().val, &mut node.borrow_mut().val)
111+
}
112+
return (None, None, true);
113+
}
114+
(if l_min.is_some() { l_min } else { Some(node.clone()) },
115+
if r_max.is_some() { r_max } else { Some(node.clone()) },
116+
false)
117+
} else {
118+
(None, None, false)
119+
}
120+
}
121+
}
122+
123+
// submission codes end
124+
125+
#[cfg(test)]
126+
mod tests {
127+
use super::*;
128+
129+
#[test]
130+
fn test_99() {
131+
let mut tree = tree![3,1,4,null,null,2];
132+
Solution::recover_tree(&mut tree);
133+
assert_eq!(tree, tree![2,1,4,null,null,3]);
134+
135+
let mut tree = tree![2,6,5,null,null,3,1,null,4];
136+
Solution::recover_tree(&mut tree);
137+
assert_eq!(tree, tree![2,1,5,null,null,3,6,null,4]);
138+
}
139+
}

src/n0100_same_tree.rs

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/**
2+
* [100] Same Tree
3+
*
4+
* Given two binary trees, write a function to check if they are the same or not.
5+
*
6+
* Two binary trees are considered the same if they are structurally identical and the nodes have the same value.
7+
*
8+
* Example 1:
9+
*
10+
*
11+
* Input: 1 1
12+
* / \ / \
13+
* 2 3 2 3
14+
*
15+
* [1,2,3], [1,2,3]
16+
*
17+
* Output: true
18+
*
19+
*
20+
* Example 2:
21+
*
22+
*
23+
* Input: 1 1
24+
* / \
25+
* 2 2
26+
*
27+
* [1,2], [1,null,2]
28+
*
29+
* Output: false
30+
*
31+
*
32+
* Example 3:
33+
*
34+
*
35+
* Input: 1 1
36+
* / \ / \
37+
* 2 1 1 2
38+
*
39+
* [1,2,1], [1,1,2]
40+
*
41+
* Output: false
42+
*
43+
*
44+
*/
45+
pub struct Solution {}
46+
47+
use super::util::tree::{TreeNode, to_tree};
48+
// submission codes start here
49+
use std::rc::Rc;
50+
use std::cell::RefCell;
51+
impl Solution {
52+
pub fn is_same_tree(p: Option<Rc<RefCell<TreeNode>>>, q: Option<Rc<RefCell<TreeNode>>>) -> bool {
53+
p == q
54+
}
55+
}
56+
57+
// submission codes end
58+
59+
#[cfg(test)]
60+
mod tests {
61+
use super::*;
62+
63+
#[test]
64+
fn test_100() {
65+
assert_eq!(Solution::is_same_tree(tree![1,2,3,4,null,5], tree![1,2,3,4,null,5]), true)
66+
}
67+
}

0 commit comments

Comments
 (0)