Skip to content

Newbee #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Sep 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions datastructure/src/list.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct ListNode {
pub val: i32,
pub next: Option<Box<ListNode>>
}
pub val: i32,
pub next: Option<Box<ListNode>>,
}

// impl TryFrom<&[i32]> for ListNode {
// type Error = &'static str;

// fn try_from(s: &[i32]) -> Result<Self, Self::Error> {

// if s.is_empty() {
// return Err("empty");
// }

// let head = ListNode {
// val: s.first().copied().unwrap(),
// next: Self::try_from(&s[1..]).ok(),
// };
// Ok(head)
// }

// }

4 changes: 2 additions & 2 deletions macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ use proc_macro::TokenStream;
mod tree_impl;
mod list_impl;

/// tree!(tree-define)
/// tree!(tree-define) => Option<Rc<RefCell<TreeNode>>>
/// tree-define: {val: int, [left: tree-define], [right: tree-define] }
#[proc_macro]
pub fn tree(input: TokenStream) -> TokenStream {
tree_impl::tree(input.into()).into()
}

/// list!(1,2,3,4)
/// list!(1,2,3,4) => Option<Box<ListNode>>
/// list!([1,2,3,4])
#[proc_macro]
pub fn list(input: TokenStream) -> TokenStream{
Expand Down
9 changes: 7 additions & 2 deletions macros/src/tree_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@ use std::str::FromStr;


pub fn tree(input: TokenStream) -> TokenStream {
let tree = TreeNode::from(input);
TokenStream::from_str(format!("{}", tree).as_str()).unwrap()
if input.is_empty(){
TokenStream::from_str("None").unwrap()
} else {
let tree = TreeNode::from(input);
TokenStream::from_str(format!("Some(::std::rc::Rc::new(::std::cell::RefCell::new({})))", tree).as_str()).unwrap()
}

}

#[derive(Debug)]
Expand Down
2 changes: 2 additions & 0 deletions src/array/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ pub mod rng;
// pub mod topological;

pub mod trie;

pub mod disjoint;
152 changes: 152 additions & 0 deletions src/array/ext/disjoint.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
//! # Disjoint-set data structure
//!
//! wiki: [Disjoint-set data structure](https://en.wikipedia.org/wiki/Disjoint-set_data_structure)
//!
//! 效果: 将数据分组
//!
//! ## 题目
//! * 简单
//! * 中等
//! * [547. 省份数量](find_circle_num)
//!

struct UnionFind {
count: usize, // 连通分量的个数, 总共分成了几组
parent: std::cell::RefCell<Vec<usize>>, // 记录每个节点的父节点,父节点为自身的是根节点
size: Vec<usize>, // 记录每个连通分量的大小
}

impl UnionFind {
pub fn new(size: usize) -> Self {
Self {
count: size,
parent: std::cell::RefCell::new((0..size).collect()),
size: vec![1; size],
}
}
pub fn count(&self) -> usize {
self.count
}
pub fn find(&self, p: usize) -> usize {
let mut root = p;
while root != self.parent.borrow()[root] {
root = self.parent.borrow()[root];
}
let mut p = p;
while p != root {
let next = self.parent.borrow()[p];
self.parent.borrow_mut()[p] = root;
p = next;
}
root
}
pub fn is_connected(&self, p: usize, q: usize) -> bool {
self.find(p) == self.find(q)
}
pub fn connect(&mut self, p: usize, q: usize) {
let (p_root, q_root) = (self.find(p), self.find(q));
if p_root == q_root {
return;
}
if self.size[p_root] < self.size[q_root] {
self.parent.borrow_mut()[p_root] = q_root;
self.size[q_root] += self.size[p_root];
} else {
self.parent.borrow_mut()[q_root] = p_root;
self.size[p_root] += self.size[q_root];
}
self.count -= 1;
}
}

/// [547. 省份数量](https://leetcode.cn/problems/number-of-provinces/)
pub fn find_circle_num(is_connected: Vec<Vec<i32>>) -> i32 {
let mut uf = UnionFind::new(is_connected.len());
is_connected.into_iter().enumerate().for_each(|(i, line)| {
line.into_iter().enumerate().for_each(|(j, x)| {
if x == 1 {
uf.connect(i, j);
}
})
});
uf.count() as i32
}

/// [684. 冗余连接](https://leetcode.cn/problems/redundant-connection/)
pub fn find_redundant_connection(edges: Vec<Vec<i32>>) -> Vec<i32> {
let mut uf = UnionFind::new(edges.len()+1);
let mut curr_count = uf.count();
let mut last_edge = vec![];

for edge in edges {
if let &[p, q] = edge.as_slice() {
uf.connect(p as usize, q as usize);
if uf.count() == curr_count {
last_edge = edge.clone();
}
curr_count = uf.count;
}
}
last_edge
}

#[cfg(test)]
mod test {
use super::*;
use crate::vec2;

#[test]
fn test_find_redundant_connection() {
struct Testcase {
edges: Vec<Vec<i32>>,
expect: Vec<i32>,
}

vec![
Testcase {
edges: vec2![[1, 2], [1, 3], [2, 3]],
expect: vec![2, 3],
},
Testcase {
edges: vec2![[1, 2], [2, 3], [3, 4], [1, 4], [1, 5]],
expect: vec![1, 4],
},
]
.into_iter()
.enumerate()
.for_each(|(idx, testcase)| {
let Testcase { edges, expect } = testcase;
let actual = find_redundant_connection(edges);
assert_eq!(expect, actual, "case {} failed", idx);
});
}

#[test]
fn test_find_circle_num() {
struct Testcase {
is_connected: Vec<Vec<i32>>,
expect: i32,
}

vec![
Testcase {
is_connected: vec2![[1, 1, 0], [1, 1, 0], [0, 0, 1]],
expect: 2,
},
Testcase {
is_connected: vec2![[1, 0, 0], [0, 1, 0], [0, 0, 1]],
expect: 3,
},
]
.into_iter()
.enumerate()
.for_each(|(idx, testcase)| {
let Testcase {
is_connected,
expect,
} = testcase;
let actual = find_circle_num(is_connected);
assert_eq!(expect, actual, "case {} failed", idx);
});
}
}
118 changes: 117 additions & 1 deletion src/array/ext/math.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
//! 数学相关题目
//! # 数学相关题目
//!
//! ## 题目
//! * 简单
//! * [1470. 重新排列数组](shuffle)
//! * [1582. 二进制矩阵中的特殊位置](num_special)
//! * 中等
//! * [462. 最小操作次数使数组元素相等 II](min_moves2)
//! * [667. 优美的排列 II](construct_array)

/// [462. 最少移动次数使数组元素相等 II](https://leetcode.cn/problems/minimum-moves-to-equal-array-elements-ii/)
///
Expand Down Expand Up @@ -126,10 +134,118 @@ pub fn construct_array(n: i32, k: i32) -> Vec<i32> {
result
}

/// [412. Fizz Buzz](https://leetcode.cn/problems/fizz-buzz/)
pub fn fizz_buzz(n: i32) -> Vec<String> {
(1..=n)
.into_iter()
.map(|num| {
if num % 3 == 0 && num % 5 == 0 {
"FizzBuzz".to_string()
} else if num % 5 == 0 {
"Buzz".to_string()
} else if num % 3 == 0 {
"Fizz".to_string()
} else {
num.to_string()
}
})
.collect()
}

/// [1342. 将数字变成 0 的操作次数](https://leetcode.cn/problems/number-of-steps-to-reduce-a-number-to-zero/)
///
/// 思路1: 模拟
/// ```
/// pub fn number_of_steps(num: i32) -> i32 {
/// let mut num = num;
/// let mut cnt = 0;
/// while num > 0 {
/// if num % 2 == 0 {
/// num = num / 2;
/// } else {
/// num = num - 1;
/// }
/// cnt += 1;
/// }
/// cnt
/// }
/// ```
///
/// 思路2: 计算
/// 将num用用二进制表示, 则每次减1, 实际对应为 低位的 1变0, 每次除2, 实际对应为 整体右移一位
/// 也就是总的操作数为可以视为 将最高位1变为0 的步数
///
/// 其中右移总共 `31 - (leading_zero)` (有符号数, 第一位为符号位, 忽略)
/// 减1 次数, 即为1的个数
///
/// 注意: 如果原本为0, 这时 `31 - (leading_zero)`可能有溢出
///
pub fn number_of_steps(num: i32) -> i32 {
(num.count_ones() + 31u32.checked_sub(num.leading_zeros()).unwrap_or(0)) as i32
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_number_of_steps() {
struct TestCase {
num: i32,
expect: i32,
}

vec![
TestCase { num: 14, expect: 6 },
TestCase { num: 8, expect: 4 },
TestCase {
num: 123,
expect: 12,
},
TestCase{num: 0, expect: 0}
]
.into_iter()
.enumerate()
.for_each(|(idx, testcase)| {
let TestCase { num, expect } = testcase;
let actual = number_of_steps(num);
assert_eq!(expect, actual, "case {} failed", idx);
});
}

#[test]
fn test_fizz_buzz() {
struct TestCase {
n: i32,
expect: Vec<&'static str>,
}

vec![
TestCase {
n: 3,
expect: vec!["1", "2", "Fizz"],
},
TestCase {
n: 5,
expect: vec!["1", "2", "Fizz", "4", "Buzz"],
},
TestCase {
n: 15,
expect: vec![
"1", "2", "Fizz", "4", "Buzz", "Fizz", "7", "8", "Fizz", "Buzz", "11", "Fizz",
"13", "14", "FizzBuzz",
],
},
]
.into_iter()
.enumerate()
.for_each(|(idx, testcase)| {
let TestCase { n, expect } = testcase;
let actual = fizz_buzz(n);
assert_eq!(expect, actual, "case {} failed", idx);
});
}

#[test]
fn test_construct_array() {
struct TestCase {
Expand Down
10 changes: 6 additions & 4 deletions src/array/ext/quick.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@
/// **快排** 主要思路是 分治, 分治可以用递归实现.
/// 步骤: 1. 确认 *轴*; 2. 根据 *轴*, 将数组切分; 3. 根据轴的位置, 递归处理每个新数组
/// 步骤一可变性不强, 可以选开头, 结尾, 中间, 随机, 方式很多不过没啥难度和技巧; 步骤三同理
/// 步骤2, 将小于x的放在x左边, 将大于x的放x右边.
///
/// 步骤2, 将小于x的放在x左边, 将大于x的放x右边, 有下面两种方式
///
/// 方式1: 使用额外数组, 挑数, 挑出来, 然后拼接在一起
/// 方式2: 快慢指针
/// * 方式1: 使用额外数组, 挑数, 挑出来, 然后拼接在一起
/// * 方式2: 快慢指针
///
/// ```rust
/// fn partition(nums: &mut [i32], left: usize, right: usize, pivot: usize) -> usize {
/// nums.swap(pivot, right);
Expand Down Expand Up @@ -51,7 +53,7 @@
/// return r;
/// }
/// ```
/// 不过思路和方式2的快慢指针是一样的, 只是用加了预处理, 将左右边界上明显不符合交换的元素, 做了跳过
/// 不过思路和方式2的快慢指针是一样的, 只是加了预处理, 将左右边界上明显不符合交换的元素, 做了跳过
///
pub fn sort_array(nums: Vec<i32>) -> Vec<i32> {
fn partition(nums: &mut [i32], left: usize, right: usize, pivot: usize) -> usize {
Expand Down
6 changes: 4 additions & 2 deletions src/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
//! 线性表相关的都会涉及
//! 比如数组(连续存储), 简单链表, 字符串(连续存储)

/// vec2![[1,2,3],[3,2,1]] => vec![vec![1,2,3], vec![3,2,1]]

/// 一些周边题目
pub mod ext;
/// 暂时不归类的题目
pub mod no_class;
/// 姑且能所做一个系列的题目
pub mod ser;
/// 暂时不归类的题目
pub mod no_class;
Loading