Skip to content

Prefix and suffix search #23

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 13 commits into from
May 4, 2021
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
12 changes: 12 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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",
]
9 changes: 9 additions & 0 deletions course_schedule_iii/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "course_schedule_iii"
version = "0.1.0"
authors = ["Ryan Li <conbas2019@gmail.com>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
81 changes: 81 additions & 0 deletions course_schedule_iii/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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<Vec<i32>>) -> 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);
}
}
9 changes: 9 additions & 0 deletions non_decreasing_array/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "non_decreasing_array"
version = "0.1.0"
authors = ["Ryan Li <conbas2019@gmail.com>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
70 changes: 70 additions & 0 deletions non_decreasing_array/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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<i32>) -> bool {
Self::check_in_sort(nums.clone()) || Self::check_reversed(nums.clone())
}

fn check_in_sort(mut nums: Vec<i32>) -> 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<i32>) -> 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));
}
}
9 changes: 9 additions & 0 deletions prefix_and_suffix_search/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "prefix_and_suffix_search"
version = "0.1.0"
authors = ["Ryan Li <conbas2019@gmail.com>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
150 changes: 150 additions & 0 deletions prefix_and_suffix_search/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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<Option<Box<Trie>>>,
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<String>) -> 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<String> {
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::<Vec<String>>();
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::<Vec<Vec<String>>>();
let result = patterns
.iter()
.map(|p| WordFilter::new(words.clone()).f(p[0].clone(), p[1].clone()))
.collect::<Vec<i32>>();
assert_eq!(result, vec![9, 4, 5, 0, 8, 1, 2, 5, 3, 1])
}
}