From 4a142685289e0a445f9f776f3e6e3bd8fb91d3f8 Mon Sep 17 00:00:00 2001 From: Gleb Koval Date: Sun, 19 Jun 2022 22:57:33 +0100 Subject: [PATCH] some more problems --- binary-tree-cameras/sol.go | 42 +++++++++ delete-operation-for-two-strings/sol.rs | 28 ++++++ longest-palindromic-substring/sol.py | 25 ++++++ longest-palindromic-substring/sol.rs | 38 +++++++++ longest-string-chain/sol.rs | 55 ++++++++++++ prefix-and-suffix-search/sol.go | 109 ++++++++++++++++++++++++ search-suggestions-system/sol.rs | 31 +++++++ 7 files changed, 328 insertions(+) create mode 100644 binary-tree-cameras/sol.go create mode 100644 delete-operation-for-two-strings/sol.rs create mode 100644 longest-palindromic-substring/sol.py create mode 100644 longest-palindromic-substring/sol.rs create mode 100644 longest-string-chain/sol.rs create mode 100644 prefix-and-suffix-search/sol.go create mode 100644 search-suggestions-system/sol.rs diff --git a/binary-tree-cameras/sol.go b/binary-tree-cameras/sol.go new file mode 100644 index 0000000..355cc53 --- /dev/null +++ b/binary-tree-cameras/sol.go @@ -0,0 +1,42 @@ +package main + +type TreeNode struct { + Val int + Left *TreeNode + Right *TreeNode +} + +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ +func minCameraCover(root *TreeNode) int { + covered := map[*TreeNode]bool{ + nil: true, + } + return dfs(root, nil, covered) +} + +func dfs(node, parent *TreeNode, covered map[*TreeNode]bool) int { + if node != nil { + out := dfs(node.Left, node, covered) + out += dfs(node.Right, node, covered) + + _, nc := covered[node] + _, lc := covered[node.Left] + _, rc := covered[node.Right] + if parent == nil && !nc || !lc || !rc { + covered[node] = true + covered[parent] = true + covered[node.Left] = true + covered[node.Right] = true + return out + 1 + } + return out + } + return 0 +} diff --git a/delete-operation-for-two-strings/sol.rs b/delete-operation-for-two-strings/sol.rs new file mode 100644 index 0000000..702e0fe --- /dev/null +++ b/delete-operation-for-two-strings/sol.rs @@ -0,0 +1,28 @@ +struct Solution{} +// Copied this from the solutions tab pretty much since I couldn't +// solve the problem myself in under O(n^2) (Time Limit Exceeded) +// Good learning problem though +impl Solution { + pub fn min_distance(word1: String, word2: String) -> i32 { + let mut dp = vec![0; word2.len() + 1]; + let (w1, w2) = (word1.chars().collect::>(), word2.chars().collect::>()); + for i in 0..word1.len() + 1 { + let mut tmp = vec![0; word2.len() + 1]; + for j in 0..word2.len() + 1 { + if (i == 0 || j == 0) { + tmp[j] = i + j; + } else if (w1[i - 1] == w2[j - 1]) { + tmp[j] = dp[j - 1]; + } else { + tmp[j] = 1 + dp[j].min(tmp[j - 1]); + } + } + dp = tmp; + } + dp[word2.len()] as i32 + } +} + +fn main() { + println!("{:?}", Solution::min_distance(String::from("ebvivhpfxoptspwianmuhmkmbhxkqbrbgpfwpfcjixzhsjmtsgrzfshvkrvoxvjpmmsrojnpgzqdyofvicscopak"), String::from("vxoumkmxbpcixzhtrfhxmnzqyvisp"))); +} \ No newline at end of file diff --git a/longest-palindromic-substring/sol.py b/longest-palindromic-substring/sol.py new file mode 100644 index 0000000..d4a8262 --- /dev/null +++ b/longest-palindromic-substring/sol.py @@ -0,0 +1,25 @@ +class Solution: + def longestPalindrome(self, s: str) -> str: + max_palindrome = "" + for idx in range(len(s)): + l, r, odd, even = idx, idx, True, True + while odd or even: + if odd: + if r == len(s) or s[l] != s[r]: + odd = False + if r - l - 1 > len(max_palindrome): + max_palindrome = s[l + 1:r] + if even: + if r == len(s) - 1 or s[l] != s[r + 1]: + even = False + if r - l > len(max_palindrome): + max_palindrome = s[l + 1:r + 1] + if l == 0: + if even and r - l + 2 > len(max_palindrome): + max_palindrome = s[l:r + 2] + elif odd and r - l + 1 > len(max_palindrome): + max_palindrome = s[l:r + 1] + break + l -= 1 + r += 1 + return max_palindrome \ No newline at end of file diff --git a/longest-palindromic-substring/sol.rs b/longest-palindromic-substring/sol.rs new file mode 100644 index 0000000..a8a4111 --- /dev/null +++ b/longest-palindromic-substring/sol.rs @@ -0,0 +1,38 @@ +impl Solution { + pub fn longest_palindrome(s: String) -> String { + let mut max = ""; + let bytes = s.as_bytes(); + for idx in 0..s.len() { + let (mut l, mut r, mut odd, mut even) = (idx, idx, true, true); + while odd || even { + if odd { + if r == s.len() || bytes[l] != bytes[r] { + odd = false; + if r - l - 1 > max.len() { + max = s.get(l + 1..r).unwrap(); + } + } + } + if even { + if r == s.len() - 1 || bytes[l] != bytes[r + 1] { + even = false; + if r - l > max.len() { + max = s.get(l + 1..r + 1).unwrap(); + } + } + } + if l == 0 { + if even && r - l + 2 > max.len() { + max = s.get(l..r + 2).unwrap(); + } else if odd && r - l + 1 > max.len() { + max = s.get(l..r + 1).unwrap(); + } + break; + } + l -= 1; + r += 1; + } + } + max.to_string() + } +} \ No newline at end of file diff --git a/longest-string-chain/sol.rs b/longest-string-chain/sol.rs new file mode 100644 index 0000000..4dc2493 --- /dev/null +++ b/longest-string-chain/sol.rs @@ -0,0 +1,55 @@ +impl Solution { + pub fn get_max_chain_len(from: &Vec>, memos: &mut Vec, start: usize) -> i32 { + let memo_val = *memos.get(start).unwrap_or(&-1); + if memo_val != -1 { + return memo_val; + } + let max_len = from.get(start) + .unwrap() + .iter() + .map(|&next| Solution::get_max_chain_len(from, memos, next)) + .max() + .unwrap_or(0) + 1; + memos[start] = max_len; + max_len + } + #[inline] + pub fn is_predecessor(word: &String, of_word: &String) -> bool { + let mut skipped = false; + let mut oi = of_word.bytes(); + of_word.len() == word.len() + 1 && word.bytes() + .all(|chr| { + if chr == oi.next().unwrap() { // Before extra character + true + } else if !skipped && chr == oi.next().unwrap() { // Extra character, skipped ensures this can only run once + skipped = true; + true + } else { + false + } + }) + } + pub fn longest_str_chain(words: Vec) -> i32 { + let (mut from, mut to) = (vec![vec![]; words.len()], vec![true; words.len()]); + for (idx1, w1) in words.iter().enumerate() { + for (idx2, w2) in words.iter().enumerate() { + if Solution::is_predecessor(w1, w2) { + from[idx1].push(idx2); + to[idx2] = false; + } + } + } + let mut memos = vec![-1; words.len()]; + to.into_iter() + .enumerate() + .filter_map(|(to, froms)| { + if froms { + Some(Solution::get_max_chain_len(&from, &mut memos, to)) + } else { + None + } + }) + .max() + .unwrap() + } +} \ No newline at end of file diff --git a/prefix-and-suffix-search/sol.go b/prefix-and-suffix-search/sol.go new file mode 100644 index 0000000..9c9b4df --- /dev/null +++ b/prefix-and-suffix-search/sol.go @@ -0,0 +1,109 @@ +package main + +type StringMap struct { + Map SubStringMap +} + +func NewStringMap() *StringMap { + return &StringMap{ + Map: map[byte]*StringMap{}, + } +} + +func (sm *StringMap) CombineAllSubStrings(prefix string, rev bool) []string { + if len(sm.Map) == 0 { + return []string{prefix} + } + out := []string{} + for chr, Map := range sm.Map { + if rev { + out = append(out, Map.CombineAllSubStrings(string(chr)+prefix, rev)...) + } else { + out = append(out, Map.CombineAllSubStrings(prefix+string(chr), rev)...) + } + } + return out +} + +func (sm *StringMap) Add(word string, rev bool) { + if len(word) == 0 { + return + } + take := 0 + if rev { + take = len(word) - 1 + } + sub, ok := sm.Map[word[take]] + if !ok { + sub = NewStringMap() + sm.Map[word[take]] = sub + } + if rev { + sub.Add(word[:take], rev) + } else { + sub.Add(word[1:], rev) + } +} + +type SubStringMap = map[byte]*StringMap + +type WordFilter struct { + Prefixes *StringMap + Suffixes *StringMap + Words map[string]int +} + +func Constructor(words []string) WordFilter { + Prefixes := NewStringMap() + Suffixes := NewStringMap() + Words := map[string]int{} + + for idx, word := range words { + Words[word] = idx + Prefixes.Add(word, false) + Suffixes.Add(word, true) + } + return WordFilter{ + Prefixes: Prefixes, + Suffixes: Suffixes, + Words: Words, + } +} + +func (wf *WordFilter) F(prefix, suffix string) int { + prefix_base, ok := wf.Prefixes, true + for i := range prefix { + prefix_base, ok = prefix_base.Map[prefix[i]] + if !ok { + return -1 + } + } + suffix_base := wf.Suffixes + for i := len(suffix) - 1; i >= 0; i-- { + suffix_base, ok = suffix_base.Map[suffix[i]] + if !ok { + return -1 + } + } + prefix_found := map[string]bool{} + for _, found := range prefix_base.CombineAllSubStrings(prefix, false) { + prefix_found[found] = true + } + + max := -1 + for _, found := range suffix_base.CombineAllSubStrings(suffix, true) { + if _, ok := prefix_found[found]; ok { + idx := wf.Words[found] + if idx > max { + max = idx + } + } + } + return max +} + +/** + * Your WordFilter object will be instantiated and called as such: + * obj := Constructor(words); + * param_1 := obj.F(prefix,suffix); + */ diff --git a/search-suggestions-system/sol.rs b/search-suggestions-system/sol.rs new file mode 100644 index 0000000..c7225b9 --- /dev/null +++ b/search-suggestions-system/sol.rs @@ -0,0 +1,31 @@ +impl Solution { + pub fn suggested_products(products: Vec, search_word: String) -> Vec> { + // Products list mapped to maximum common prefix length with search_word + let max_prefix_matches = products.iter() + .map(|product| product.bytes() + .zip(search_word.bytes()) + .take_while(|&(chr1, chr2)| chr1 == chr2) + .count() + ) + .collect::>(); + search_word.bytes() + .enumerate() + .map(|(chr_idx, chr)| { + // Get all options that match at least chr_idx prefix length + let mut options = max_prefix_matches.iter() + .enumerate() + .filter_map(|(product_idx, &max_prefix_match)| { + if max_prefix_match > chr_idx { + Some(&products[product_idx]) + } else { None } + }) + .collect::>(); + options.sort(); // TODO : Could optimise since we are only taking 3 smallest elements + options.into_iter() + .take(3) + .map(|s| s.clone()) + .collect() + }) + .collect() + } +} \ No newline at end of file