Skip to content

Commit 2f07492

Browse files
authored
Merge pull request #23 from jtr109/prefix-and-suffix-search
Prefix and suffix search
2 parents 3c576fd + f485c6e commit 2f07492

File tree

8 files changed

+343
-0
lines changed

8 files changed

+343
-0
lines changed

Cargo.lock

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,7 @@ members = [
1313
"reverse_words_in_a_string_iii",
1414
"edit_distance",
1515
"running_sum_of_1d_array",
16+
"course_schedule_iii",
17+
"prefix_and_suffix_search",
18+
"non_decreasing_array",
1619
]

course_schedule_iii/Cargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "course_schedule_iii"
3+
version = "0.1.0"
4+
authors = ["Ryan Li <conbas2019@gmail.com>"]
5+
edition = "2018"
6+
7+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8+
9+
[dependencies]

course_schedule_iii/src/lib.rs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* [Explore - LeetCode](https://leetcode.com/explore/featured/card/may-leetcoding-challenge-2021/598/week-1-may-1st-may-7th/3729/)
3+
*/
4+
5+
use std::collections::BinaryHeap;
6+
7+
pub struct Solution {}
8+
9+
impl Solution {
10+
pub fn schedule_course(courses: Vec<Vec<i32>>) -> i32 {
11+
// order by deadline
12+
let mut courses = courses;
13+
courses.sort_by(|x, y| x[1].cmp(&y[1]));
14+
let mut deadline = 0;
15+
let mut selected = BinaryHeap::new();
16+
for c in courses.iter() {
17+
let duration = c[0];
18+
let last_day = c[1];
19+
if deadline + duration <= last_day {
20+
selected.push(c);
21+
deadline += duration;
22+
continue;
23+
}
24+
if selected.len() > 0
25+
&& selected.peek().unwrap()[0] > duration
26+
&& deadline - selected.peek().unwrap()[0] + duration <= last_day
27+
{
28+
let max = selected.pop().unwrap();
29+
selected.push(c);
30+
deadline = deadline - max[0] + duration;
31+
continue;
32+
}
33+
}
34+
selected.len() as i32
35+
}
36+
}
37+
38+
#[cfg(test)]
39+
mod tests {
40+
use super::*;
41+
42+
#[test]
43+
fn test_example_1() {
44+
let courses = vec![
45+
vec![100, 200],
46+
vec![200, 1300],
47+
vec![1000, 1250],
48+
vec![2000, 3200],
49+
];
50+
assert_eq!(Solution::schedule_course(courses), 3);
51+
}
52+
53+
#[test]
54+
fn test_example_2() {
55+
let courses = vec![vec![1, 2]];
56+
assert_eq!(Solution::schedule_course(courses), 1);
57+
}
58+
59+
#[test]
60+
fn test_example_3() {
61+
let courses = vec![vec![3, 2], vec![4, 3]];
62+
assert_eq!(Solution::schedule_course(courses), 0);
63+
}
64+
65+
#[test]
66+
fn test_submission_1() {
67+
let courses = vec![
68+
vec![7, 16],
69+
vec![2, 3],
70+
vec![3, 12],
71+
vec![3, 14],
72+
vec![10, 19],
73+
vec![10, 16],
74+
vec![6, 8],
75+
vec![6, 11],
76+
vec![3, 13],
77+
vec![6, 16],
78+
];
79+
assert_eq!(Solution::schedule_course(courses), 4);
80+
}
81+
}

non_decreasing_array/Cargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "non_decreasing_array"
3+
version = "0.1.0"
4+
authors = ["Ryan Li <conbas2019@gmail.com>"]
5+
edition = "2018"
6+
7+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8+
9+
[dependencies]

non_decreasing_array/src/lib.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* https://leetcode.com/explore/challenge/card/may-leetcoding-challenge-2021/598/week-1-may-1st-may-7th/3731/
3+
*/
4+
5+
pub struct Solution {}
6+
7+
impl Solution {
8+
pub fn check_possibility(nums: Vec<i32>) -> bool {
9+
Self::check_in_sort(nums.clone()) || Self::check_reversed(nums.clone())
10+
}
11+
12+
fn check_in_sort(mut nums: Vec<i32>) -> bool {
13+
let mut increase_exists = false;
14+
for i in 0..nums.len() - 1 {
15+
if nums[i] <= nums[i + 1] {
16+
continue;
17+
}
18+
if increase_exists {
19+
return false;
20+
}
21+
nums[i + 1] = nums[i];
22+
increase_exists = true;
23+
}
24+
true
25+
}
26+
27+
fn check_reversed(mut nums: Vec<i32>) -> bool {
28+
let mut increase_exists = false;
29+
for i in (0..nums.len() - 1).rev() {
30+
if nums[i] <= nums[i + 1] {
31+
continue;
32+
}
33+
if increase_exists {
34+
return false;
35+
}
36+
nums[i] = nums[i + 1];
37+
increase_exists = true;
38+
}
39+
true
40+
}
41+
}
42+
43+
#[cfg(test)]
44+
mod test {
45+
use super::*;
46+
47+
#[test]
48+
fn example_1() {
49+
let nums = vec![4, 2, 3];
50+
assert!(Solution::check_possibility(nums));
51+
}
52+
53+
#[test]
54+
fn example_2() {
55+
let nums = vec![4, 2, 1];
56+
assert!(!Solution::check_possibility(nums));
57+
}
58+
59+
#[test]
60+
fn submission_1() {
61+
let nums = vec![3, 4, 2, 3];
62+
assert!(!Solution::check_possibility(nums));
63+
}
64+
65+
#[test]
66+
fn submission_2() {
67+
let nums = vec![5, 7, 1, 8];
68+
assert!(Solution::check_possibility(nums));
69+
}
70+
}

prefix_and_suffix_search/Cargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "prefix_and_suffix_search"
3+
version = "0.1.0"
4+
authors = ["Ryan Li <conbas2019@gmail.com>"]
5+
edition = "2018"
6+
7+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8+
9+
[dependencies]

prefix_and_suffix_search/src/lib.rs

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/*
2+
* [Explore - LeetCode](https://leetcode.com/explore/challenge/card/may-leetcoding-challenge-2021/598/week-1-may-1st-may-7th/3728/)
3+
*
4+
* Your WordFilter object will be instantiated and called as such:
5+
* let obj = WordFilter::new(words);
6+
* let ret_1: i32 = obj.f(prefix, suffix);
7+
*/
8+
9+
#[derive(Clone)]
10+
struct Trie {
11+
children: Vec<Option<Box<Trie>>>,
12+
index: i32,
13+
}
14+
15+
impl Trie {
16+
fn get_char_index(c: char) -> usize {
17+
if c as usize >= 'a' as usize && c as usize <= 'z' as usize {
18+
c as usize - 'a' as usize
19+
} else {
20+
26
21+
}
22+
}
23+
24+
fn new() -> Self {
25+
Self {
26+
children: vec![None; 27],
27+
index: -1,
28+
}
29+
}
30+
31+
fn add(&mut self, index: usize, chars: &str) {
32+
match chars.chars().nth(0) {
33+
None => (),
34+
Some(c) => {
35+
let c_index = Self::get_char_index(c);
36+
let child = self.children[c_index].get_or_insert(Box::new(Self::new()));
37+
child.add(index, &chars[1..]);
38+
}
39+
}
40+
self.index = index as i32; // mark index on the whole branch
41+
}
42+
43+
fn search(&self, chars: &str) -> i32 {
44+
match chars.chars().nth(0) {
45+
None => self.index,
46+
Some(c) => {
47+
let c_index = Self::get_char_index(c);
48+
match &self.children[c_index] {
49+
None => -1,
50+
Some(child) => child.search(&chars[1..]),
51+
}
52+
}
53+
}
54+
}
55+
}
56+
57+
pub struct WordFilter {
58+
trie: Trie,
59+
}
60+
61+
impl WordFilter {
62+
pub fn new(words: Vec<String>) -> Self {
63+
let mut trie = Trie::new();
64+
for (index, word) in words.iter().enumerate() {
65+
for pattern in Self::all_patterns(word).iter() {
66+
trie.add(index, pattern);
67+
}
68+
}
69+
WordFilter { trie }
70+
}
71+
72+
fn all_patterns(word: &str) -> Vec<String> {
73+
let mut res = vec![];
74+
for i in 0..word.len() {
75+
res.push(String::new() + &word[i..word.len()] + "#" + &word);
76+
}
77+
res
78+
}
79+
80+
pub fn f(&self, prefix: String, suffix: String) -> i32 {
81+
self.trie.search(&(String::new() + &suffix + "#" + &prefix))
82+
}
83+
}
84+
85+
#[cfg(test)]
86+
mod test {
87+
use super::*;
88+
89+
#[test]
90+
fn test_trie() {
91+
let mut root = Trie::new();
92+
root.add(0, "foo");
93+
root.add(1, "bar");
94+
root.add(3, "biz");
95+
assert_eq!(root.search("foo"), 0);
96+
assert_eq!(root.search("bar"), 1);
97+
assert_eq!(root.search("biz"), 3);
98+
assert_eq!(root.search("buz"), -1);
99+
assert_eq!(root.search("fo"), 0);
100+
assert_eq!(root.search("b"), 3);
101+
}
102+
103+
#[test]
104+
fn example_1() {
105+
let words = vec!["apple"].iter().map(|s| s.to_string()).collect();
106+
let prefix = "a".to_string();
107+
let suffix = "e".to_string();
108+
let expected = 0;
109+
assert_eq!(WordFilter::new(words).f(prefix, suffix), expected);
110+
}
111+
112+
#[test]
113+
fn submission_1() {
114+
let words = vec![
115+
"cabaabaaaa",
116+
"ccbcababac",
117+
"bacaabccba",
118+
"bcbbcbacaa",
119+
"abcaccbcaa",
120+
"accabaccaa",
121+
"cabcbbbcca",
122+
"ababccabcb",
123+
"caccbbcbab",
124+
"bccbacbcba",
125+
]
126+
.iter()
127+
.map(|w| w.to_string())
128+
.collect::<Vec<String>>();
129+
let patterns = vec![
130+
vec!["bccbacbcba", "a"],
131+
vec!["ab", "abcaccbcaa"],
132+
vec!["a", "aa"],
133+
vec!["cabaaba", "abaaaa"],
134+
vec!["cacc", "accbbcbab"],
135+
vec!["ccbcab", "bac"],
136+
vec!["bac", "cba"],
137+
vec!["ac", "accabaccaa"],
138+
vec!["bcbb", "aa"],
139+
vec!["ccbca", "cbcababac"],
140+
]
141+
.iter()
142+
.map(|p| vec![p[0].to_string(), p[1].to_string()])
143+
.collect::<Vec<Vec<String>>>();
144+
let result = patterns
145+
.iter()
146+
.map(|p| WordFilter::new(words.clone()).f(p[0].clone(), p[1].clone()))
147+
.collect::<Vec<i32>>();
148+
assert_eq!(result, vec![9, 4, 5, 0, 8, 1, 2, 5, 3, 1])
149+
}
150+
}

0 commit comments

Comments
 (0)