diff --git a/Cargo.lock b/Cargo.lock index 1400ea9..9395000 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,6 +4,10 @@ name = "binary_tree_postorder_traversal" version = "0.1.0" +[[package]] +name = "course_schedule_iii" +version = "0.1.0" + [[package]] name = "edit_distance" version = "0.1.0" @@ -28,6 +32,14 @@ version = "0.1.0" name = "merge_sorted_array" version = "0.1.0" +[[package]] +name = "non_decreasing_array" +version = "0.1.0" + +[[package]] +name = "prefix_and_suffix_search" +version = "0.1.0" + [[package]] name = "reverse_integer" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 6187d46..24e2beb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,4 +13,7 @@ members = [ "reverse_words_in_a_string_iii", "edit_distance", "running_sum_of_1d_array", + "course_schedule_iii", + "prefix_and_suffix_search", + "non_decreasing_array", ] diff --git a/course_schedule_iii/Cargo.toml b/course_schedule_iii/Cargo.toml new file mode 100644 index 0000000..629cb7d --- /dev/null +++ b/course_schedule_iii/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "course_schedule_iii" +version = "0.1.0" +authors = ["Ryan Li "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/course_schedule_iii/src/lib.rs b/course_schedule_iii/src/lib.rs new file mode 100644 index 0000000..60e8c64 --- /dev/null +++ b/course_schedule_iii/src/lib.rs @@ -0,0 +1,81 @@ +/* + * [Explore - LeetCode](https://leetcode.com/explore/featured/card/may-leetcoding-challenge-2021/598/week-1-may-1st-may-7th/3729/) + */ + +use std::collections::BinaryHeap; + +pub struct Solution {} + +impl Solution { + pub fn schedule_course(courses: Vec>) -> i32 { + // order by deadline + let mut courses = courses; + courses.sort_by(|x, y| x[1].cmp(&y[1])); + let mut deadline = 0; + let mut selected = BinaryHeap::new(); + for c in courses.iter() { + let duration = c[0]; + let last_day = c[1]; + if deadline + duration <= last_day { + selected.push(c); + deadline += duration; + continue; + } + if selected.len() > 0 + && selected.peek().unwrap()[0] > duration + && deadline - selected.peek().unwrap()[0] + duration <= last_day + { + let max = selected.pop().unwrap(); + selected.push(c); + deadline = deadline - max[0] + duration; + continue; + } + } + selected.len() as i32 + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_example_1() { + let courses = vec![ + vec![100, 200], + vec![200, 1300], + vec![1000, 1250], + vec![2000, 3200], + ]; + assert_eq!(Solution::schedule_course(courses), 3); + } + + #[test] + fn test_example_2() { + let courses = vec![vec![1, 2]]; + assert_eq!(Solution::schedule_course(courses), 1); + } + + #[test] + fn test_example_3() { + let courses = vec![vec![3, 2], vec![4, 3]]; + assert_eq!(Solution::schedule_course(courses), 0); + } + + #[test] + fn test_submission_1() { + let courses = vec![ + vec![7, 16], + vec![2, 3], + vec![3, 12], + vec![3, 14], + vec![10, 19], + vec![10, 16], + vec![6, 8], + vec![6, 11], + vec![3, 13], + vec![6, 16], + ]; + assert_eq!(Solution::schedule_course(courses), 4); + } +} diff --git a/non_decreasing_array/Cargo.toml b/non_decreasing_array/Cargo.toml new file mode 100644 index 0000000..f4cf175 --- /dev/null +++ b/non_decreasing_array/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "non_decreasing_array" +version = "0.1.0" +authors = ["Ryan Li "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/non_decreasing_array/src/lib.rs b/non_decreasing_array/src/lib.rs new file mode 100644 index 0000000..70f1839 --- /dev/null +++ b/non_decreasing_array/src/lib.rs @@ -0,0 +1,70 @@ +/* + * https://leetcode.com/explore/challenge/card/may-leetcoding-challenge-2021/598/week-1-may-1st-may-7th/3731/ + */ + +pub struct Solution {} + +impl Solution { + pub fn check_possibility(nums: Vec) -> bool { + Self::check_in_sort(nums.clone()) || Self::check_reversed(nums.clone()) + } + + fn check_in_sort(mut nums: Vec) -> bool { + let mut increase_exists = false; + for i in 0..nums.len() - 1 { + if nums[i] <= nums[i + 1] { + continue; + } + if increase_exists { + return false; + } + nums[i + 1] = nums[i]; + increase_exists = true; + } + true + } + + fn check_reversed(mut nums: Vec) -> bool { + let mut increase_exists = false; + for i in (0..nums.len() - 1).rev() { + if nums[i] <= nums[i + 1] { + continue; + } + if increase_exists { + return false; + } + nums[i] = nums[i + 1]; + increase_exists = true; + } + true + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn example_1() { + let nums = vec![4, 2, 3]; + assert!(Solution::check_possibility(nums)); + } + + #[test] + fn example_2() { + let nums = vec![4, 2, 1]; + assert!(!Solution::check_possibility(nums)); + } + + #[test] + fn submission_1() { + let nums = vec![3, 4, 2, 3]; + assert!(!Solution::check_possibility(nums)); + } + + #[test] + fn submission_2() { + let nums = vec![5, 7, 1, 8]; + assert!(Solution::check_possibility(nums)); + } +} diff --git a/prefix_and_suffix_search/Cargo.toml b/prefix_and_suffix_search/Cargo.toml new file mode 100644 index 0000000..fbbe109 --- /dev/null +++ b/prefix_and_suffix_search/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "prefix_and_suffix_search" +version = "0.1.0" +authors = ["Ryan Li "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/prefix_and_suffix_search/src/lib.rs b/prefix_and_suffix_search/src/lib.rs new file mode 100644 index 0000000..781de2e --- /dev/null +++ b/prefix_and_suffix_search/src/lib.rs @@ -0,0 +1,150 @@ +/* + * [Explore - LeetCode](https://leetcode.com/explore/challenge/card/may-leetcoding-challenge-2021/598/week-1-may-1st-may-7th/3728/) + * + * Your WordFilter object will be instantiated and called as such: + * let obj = WordFilter::new(words); + * let ret_1: i32 = obj.f(prefix, suffix); + */ + +#[derive(Clone)] +struct Trie { + children: Vec>>, + index: i32, +} + +impl Trie { + fn get_char_index(c: char) -> usize { + if c as usize >= 'a' as usize && c as usize <= 'z' as usize { + c as usize - 'a' as usize + } else { + 26 + } + } + + fn new() -> Self { + Self { + children: vec![None; 27], + index: -1, + } + } + + fn add(&mut self, index: usize, chars: &str) { + match chars.chars().nth(0) { + None => (), + Some(c) => { + let c_index = Self::get_char_index(c); + let child = self.children[c_index].get_or_insert(Box::new(Self::new())); + child.add(index, &chars[1..]); + } + } + self.index = index as i32; // mark index on the whole branch + } + + fn search(&self, chars: &str) -> i32 { + match chars.chars().nth(0) { + None => self.index, + Some(c) => { + let c_index = Self::get_char_index(c); + match &self.children[c_index] { + None => -1, + Some(child) => child.search(&chars[1..]), + } + } + } + } +} + +pub struct WordFilter { + trie: Trie, +} + +impl WordFilter { + pub fn new(words: Vec) -> Self { + let mut trie = Trie::new(); + for (index, word) in words.iter().enumerate() { + for pattern in Self::all_patterns(word).iter() { + trie.add(index, pattern); + } + } + WordFilter { trie } + } + + fn all_patterns(word: &str) -> Vec { + let mut res = vec![]; + for i in 0..word.len() { + res.push(String::new() + &word[i..word.len()] + "#" + &word); + } + res + } + + pub fn f(&self, prefix: String, suffix: String) -> i32 { + self.trie.search(&(String::new() + &suffix + "#" + &prefix)) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_trie() { + let mut root = Trie::new(); + root.add(0, "foo"); + root.add(1, "bar"); + root.add(3, "biz"); + assert_eq!(root.search("foo"), 0); + assert_eq!(root.search("bar"), 1); + assert_eq!(root.search("biz"), 3); + assert_eq!(root.search("buz"), -1); + assert_eq!(root.search("fo"), 0); + assert_eq!(root.search("b"), 3); + } + + #[test] + fn example_1() { + let words = vec!["apple"].iter().map(|s| s.to_string()).collect(); + let prefix = "a".to_string(); + let suffix = "e".to_string(); + let expected = 0; + assert_eq!(WordFilter::new(words).f(prefix, suffix), expected); + } + + #[test] + fn submission_1() { + let words = vec![ + "cabaabaaaa", + "ccbcababac", + "bacaabccba", + "bcbbcbacaa", + "abcaccbcaa", + "accabaccaa", + "cabcbbbcca", + "ababccabcb", + "caccbbcbab", + "bccbacbcba", + ] + .iter() + .map(|w| w.to_string()) + .collect::>(); + let patterns = vec![ + vec!["bccbacbcba", "a"], + vec!["ab", "abcaccbcaa"], + vec!["a", "aa"], + vec!["cabaaba", "abaaaa"], + vec!["cacc", "accbbcbab"], + vec!["ccbcab", "bac"], + vec!["bac", "cba"], + vec!["ac", "accabaccaa"], + vec!["bcbb", "aa"], + vec!["ccbca", "cbcababac"], + ] + .iter() + .map(|p| vec![p[0].to_string(), p[1].to_string()]) + .collect::>>(); + let result = patterns + .iter() + .map(|p| WordFilter::new(words.clone()).f(p[0].clone(), p[1].clone())) + .collect::>(); + assert_eq!(result, vec![9, 4, 5, 0, 8, 1, 2, 5, 3, 1]) + } +}