From cede8e5f4507ceeae386743f6899da7a78c835d1 Mon Sep 17 00:00:00 2001 From: erius Date: Tue, 23 Apr 2024 04:21:09 +0300 Subject: [PATCH] Moved every rust file from src/bin to src, added tests for each problem, added lib.rs file --- src/bin/10_regular_expression_matching.rs | 20 -------- src/bin/11_container_with_most_water.rs | 20 -------- src/bin/12_integer_to_roman.rs | 35 ------------- src/bin/13_roman_to_integer.rs | 13 ----- src/bin/14_longest_common_prefix.rs | 19 ------- src/bin/15_3sum.rs | 31 ------------ src/bin/16_3sum_closest.rs | 8 --- src/bin/1_two_sum.rs | 17 ------- src/bin/2_add_two_numbers.rs | 46 ----------------- ..._substring_without_repeating_characters.rs | 20 -------- src/bin/4_median_of_two_sorted_arrays.rs | 22 -------- src/bin/5_longest_palindrome_substring.rs | 17 ------- src/bin/6_zigzag_conversion.rs | 20 -------- src/bin/7_reverse_integer.rs | 19 ------- src/bin/8_string_to_integer.rs | 21 -------- src/bin/9_palindrome_number.rs | 14 ------ src/lib.rs | 16 ++++++ src/p10_regular_expression_matching.rs | 34 +++++++++++++ src/p11_container_with_most_water.rs | 29 +++++++++++ src/p12_integer_to_roman.rs | 49 ++++++++++++++++++ src/p13_roman_to_integer.rs | 27 ++++++++++ src/p14_longest_common_prefix.rs | 30 +++++++++++ src/p15_3sum.rs | 43 ++++++++++++++++ src/p16_3sum_closest.rs | 17 +++++++ src/p1_two_sum.rs | 35 +++++++++++++ src/p2_add_two_numbers.rs | 50 +++++++++++++++++++ ..._substring_without_repeating_characters.rs | 34 +++++++++++++ src/p4_median_of_two_sorted_arrays.rs | 31 ++++++++++++ src/p5_longest_palindrome_substring.rs | 27 ++++++++++ src/p6_zigzag_conversion.rs | 34 +++++++++++++ src/p7_reverse_integer.rs | 33 ++++++++++++ src/p8_string_to_integer.rs | 35 +++++++++++++ src/p9_palindrome_number.rs | 28 +++++++++++ 33 files changed, 552 insertions(+), 342 deletions(-) delete mode 100644 src/bin/10_regular_expression_matching.rs delete mode 100644 src/bin/11_container_with_most_water.rs delete mode 100644 src/bin/12_integer_to_roman.rs delete mode 100644 src/bin/13_roman_to_integer.rs delete mode 100644 src/bin/14_longest_common_prefix.rs delete mode 100644 src/bin/15_3sum.rs delete mode 100644 src/bin/16_3sum_closest.rs delete mode 100644 src/bin/1_two_sum.rs delete mode 100644 src/bin/2_add_two_numbers.rs delete mode 100644 src/bin/3_longest_substring_without_repeating_characters.rs delete mode 100644 src/bin/4_median_of_two_sorted_arrays.rs delete mode 100644 src/bin/5_longest_palindrome_substring.rs delete mode 100644 src/bin/6_zigzag_conversion.rs delete mode 100644 src/bin/7_reverse_integer.rs delete mode 100644 src/bin/8_string_to_integer.rs delete mode 100644 src/bin/9_palindrome_number.rs create mode 100644 src/lib.rs create mode 100644 src/p10_regular_expression_matching.rs create mode 100644 src/p11_container_with_most_water.rs create mode 100644 src/p12_integer_to_roman.rs create mode 100644 src/p13_roman_to_integer.rs create mode 100644 src/p14_longest_common_prefix.rs create mode 100644 src/p15_3sum.rs create mode 100644 src/p16_3sum_closest.rs create mode 100644 src/p1_two_sum.rs create mode 100644 src/p2_add_two_numbers.rs create mode 100644 src/p3_longest_substring_without_repeating_characters.rs create mode 100644 src/p4_median_of_two_sorted_arrays.rs create mode 100644 src/p5_longest_palindrome_substring.rs create mode 100644 src/p6_zigzag_conversion.rs create mode 100644 src/p7_reverse_integer.rs create mode 100644 src/p8_string_to_integer.rs create mode 100644 src/p9_palindrome_number.rs diff --git a/src/bin/10_regular_expression_matching.rs b/src/bin/10_regular_expression_matching.rs deleted file mode 100644 index 19f173d..0000000 --- a/src/bin/10_regular_expression_matching.rs +++ /dev/null @@ -1,20 +0,0 @@ -fn main() { - println!("{}", is_match(String::from("acaabbaccbbacaabbbb"), String::from("a*.*b*.*a*aa*a*"))) -} - -pub fn is_match(s: String, p: String) -> bool { - let (s, p) = (s.as_bytes(), p.as_bytes()); - let mut dp = vec![vec![false; p.len() + 1]; s.len() + 1]; - dp[s.len()][p.len()] = true; - for i in (0..=s.len()).rev() { - for j in (0..p.len()).rev() { - let first_match = i < s.len() && (p[j] == b'.' || p[j] == s[i]); - if j + 1 < p.len() && p[j + 1] == b'*' { - dp[i][j] = first_match && dp[i + 1][j] || dp[i][j + 2]; - continue; - } - dp[i][j] = first_match && dp[i + 1][j + 1]; - } - } - return dp[0][0]; -} diff --git a/src/bin/11_container_with_most_water.rs b/src/bin/11_container_with_most_water.rs deleted file mode 100644 index 5937f31..0000000 --- a/src/bin/11_container_with_most_water.rs +++ /dev/null @@ -1,20 +0,0 @@ -fn main() { - println!("{}", max_area(vec![1,8,6,2,5,4,8,3,7])); -} - -pub fn max_area(height: Vec) -> i32 { - let (mut left, mut right) = (0, height.len() - 1); - let mut max_water = 0; - while left < right { - let x = (right - left) as i32; let h; - if height[left] < height[right] { - h = height[left]; - left += 1; - } else { - h = height[right]; - right -= 1; - }; - max_water = max_water.max(h * x); - } - return max_water; -} diff --git a/src/bin/12_integer_to_roman.rs b/src/bin/12_integer_to_roman.rs deleted file mode 100644 index 58a44bf..0000000 --- a/src/bin/12_integer_to_roman.rs +++ /dev/null @@ -1,35 +0,0 @@ -fn main() { - println!("{}", int_to_roman(1994)); -} - -pub fn int_to_roman(num: i32) -> String { - let roman_nums = vec!['M', 'D', 'C', 'L', 'X', 'V', 'I']; - let mut result = String::with_capacity(15); - let (mut num, mut divisor) = (num, 1000); - for i in (0..roman_nums.len()).step_by(2) { - let roman = roman_nums[i]; - let roman_amount = num / divisor; - match roman_amount { - 0 => (), - 1..=3 => { - for _ in 0..roman_amount { result.push(roman); } - }, - 5..=8 => { - let complement = roman_nums[i - 1]; - result.push(complement); - for _ in 0..(roman_amount-5) { result.push(roman); } - }, - 4 | 9 => { - let complement_index = i - roman_amount as usize / 4; - let complement = roman_nums[complement_index]; - result.push(roman); - result.push(complement); - }, - _ => () - } - num %= divisor; - divisor /= 10; - } - if result.is_empty() { result.push('0'); } - return result; -} diff --git a/src/bin/13_roman_to_integer.rs b/src/bin/13_roman_to_integer.rs deleted file mode 100644 index c345340..0000000 --- a/src/bin/13_roman_to_integer.rs +++ /dev/null @@ -1,13 +0,0 @@ -fn main() { - println!("{}", roman_to_int(String::from("MCMXCIV"))); -} - -pub fn roman_to_int(s: String) -> i32 { - s.chars().fold(0, |acc, c| { - let num = match c { - 'M' => 1000, 'D' => 500, 'C' => 100, 'L' => 50, - 'X' => 10, 'V' => 5, 'I' => 1, _ => 0 - }; - acc + num - 2 * (acc % num) - }) -} diff --git a/src/bin/14_longest_common_prefix.rs b/src/bin/14_longest_common_prefix.rs deleted file mode 100644 index c1f1d99..0000000 --- a/src/bin/14_longest_common_prefix.rs +++ /dev/null @@ -1,19 +0,0 @@ -fn main() { - -} - -pub fn longest_common_prefix(strs: Vec) -> String { - let mut result = String::with_capacity(200); - let first_str = strs[0].as_bytes(); - if first_str.is_empty() { return result; } - for i in 0..first_str.len() { - let c = first_str[i]; - for j in 1..strs.len() { - if i >= strs[j].len() || c != strs[j].as_bytes()[i] { - return result; - } - } - result.push(c as char); - } - return result; -} diff --git a/src/bin/15_3sum.rs b/src/bin/15_3sum.rs deleted file mode 100644 index 27f0fd2..0000000 --- a/src/bin/15_3sum.rs +++ /dev/null @@ -1,31 +0,0 @@ -fn main() { - println!("{:?}", three_sum(vec![-1,0,1,2,-1,-4])); - println!("{:?}", three_sum(vec![0,0,0,0,0,0])); - println!("{:?}", three_sum(vec![-2,0,0,2,2])); -} - -pub fn three_sum(mut nums: Vec) -> Vec> { - let mut result = Vec::>::new(); - nums.sort(); - for i in 0..nums.len()-2 { - if i > 0 && nums[i] == nums[i - 1] { continue; } - let (mut j, mut k) = (i + 1, nums.len() - 1); - while j < k { - if j > i + 1 && nums[j - 1] == nums[j] { - j += 1; continue; - } - if k < nums.len() - 1 && nums[k + 1] == nums[k] { - k -= 1; continue; - } - match (nums[i] + nums[j] + nums[k]).cmp(&0) { - std::cmp::Ordering::Less => { j += 1; }, - std::cmp::Ordering::Greater => { k -= 1 }, - std::cmp::Ordering::Equal => { - result.push(vec![nums[i], nums[j], nums[k]]); - j += 1; k -= 1; - } - } - } - } - return result; -} diff --git a/src/bin/16_3sum_closest.rs b/src/bin/16_3sum_closest.rs deleted file mode 100644 index ac71fee..0000000 --- a/src/bin/16_3sum_closest.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - -} - -pub fn three_sum_closest(nums: Vec, target: i32) -> i32 { - - return 0; -} diff --git a/src/bin/1_two_sum.rs b/src/bin/1_two_sum.rs deleted file mode 100644 index 1eb1415..0000000 --- a/src/bin/1_two_sum.rs +++ /dev/null @@ -1,17 +0,0 @@ -use std::collections::HashMap; - -fn main() { - println!("{:?}", two_sum(vec![2,7,11,15], 9)); -} - -pub fn two_sum(nums: Vec, target: i32) -> Vec { - let mut components: HashMap = HashMap::new(); - for i in 0..nums.len() { - let component = target - nums[i]; - if let Some(j) = components.get(&component) { - return vec![i as i32, *j as i32]; - } - components.insert(nums[i], i); - } - return Vec::new(); -} diff --git a/src/bin/2_add_two_numbers.rs b/src/bin/2_add_two_numbers.rs deleted file mode 100644 index f0997eb..0000000 --- a/src/bin/2_add_two_numbers.rs +++ /dev/null @@ -1,46 +0,0 @@ -fn main() { - -} - -pub fn add_two_numbers(l1: Option>, l2: Option>) -> Option> { - let (mut l1, mut l2) = (l1, l2); - let mut head = Box::new(ListNode::new(0)); - let mut tail = &mut head; - loop { - let mut sum = tail.val; - if let Some(node) = &l1 { - sum += node.val; - l1 = node.next.clone(); - } - if let Some(node) = &l2 { - sum += node.val; - l2 = node.next.clone(); - } - let next_node = Box::new(ListNode::new(sum / 10)); - tail.val = sum % 10; - if l1.is_none() && l2.is_none() { - if next_node.val > 0 { tail.next = Some(next_node); } - break; - } - tail.next = Some(next_node); - tail = tail.next.as_mut().unwrap(); - } - return Some(head); -} - -// Definition for singly-linked list. -#[derive(PartialEq, Eq, Clone, Debug)] -pub struct ListNode { - pub val: i32, - pub next: Option> -} - -impl ListNode { - #[inline] - fn new(val: i32) -> Self { - ListNode { - next: None, - val - } - } -} diff --git a/src/bin/3_longest_substring_without_repeating_characters.rs b/src/bin/3_longest_substring_without_repeating_characters.rs deleted file mode 100644 index 6abc5f5..0000000 --- a/src/bin/3_longest_substring_without_repeating_characters.rs +++ /dev/null @@ -1,20 +0,0 @@ -use std::collections::HashMap; - -fn main() { - println!("{}", length_of_longest_substring(String::from("abcabcbb"))); -} - -pub fn length_of_longest_substring(s: String) -> i32 { - let mut seen: HashMap = HashMap::with_capacity(80); - let (mut start_index, mut max_length) = (0usize, 0usize); - for (i, c) in s.chars().enumerate() { - if let Some(index) = seen.get(&c) { - max_length = max_length.max(i - start_index); - start_index = *index + 1; - seen.retain(|_, i| *i >= start_index); - } - seen.insert(c, i); - } - max_length = max_length.max(s.len() - start_index); - return max_length as i32; -} diff --git a/src/bin/4_median_of_two_sorted_arrays.rs b/src/bin/4_median_of_two_sorted_arrays.rs deleted file mode 100644 index c7b1f09..0000000 --- a/src/bin/4_median_of_two_sorted_arrays.rs +++ /dev/null @@ -1,22 +0,0 @@ -fn main() { - -} - -// TODO: reduce algorithm complexity from O(m+n) to O(log(m+n)) -pub fn find_median_sorted_arrays(nums1: Vec, nums2: Vec) -> f64 { - let length = nums1.len() + nums2.len(); - let mut nums3 = vec![0i32; length]; - let (mut m, mut n) = (0usize, 0usize); - while m + n < length { - let x1 = if m < nums1.len() { nums1[m] } else { i32::MAX }; - let x2 = if n < nums2.len() { nums2[n] } else { i32::MAX }; - if x1 <= x2 { - nums3[m + n] = x1; - m += 1; - } else { - nums3[m + n] = x2; - n += 1; - } - } - return (nums3[(length - 1) / 2] + nums3[length / 2]) as f64 / 2.0; -} diff --git a/src/bin/5_longest_palindrome_substring.rs b/src/bin/5_longest_palindrome_substring.rs deleted file mode 100644 index 07897de..0000000 --- a/src/bin/5_longest_palindrome_substring.rs +++ /dev/null @@ -1,17 +0,0 @@ -fn main() { - println!("{}", longest_palindrome(String::from("bb"))); -} - -pub fn longest_palindrome(s: String) -> String { - let mut max_indexes = (0usize, 1usize); - for i in 0..(s.len()-1)*2 { - let (mut start, mut end) = (i / 2 + i % 2, i / 2); - while start > 0 && end < s.len() - 1 { - if s.as_bytes()[start - 1] != s.as_bytes()[end + 1] { break; } - start -= 1; end += 1; - } - let length = end + 1 - start; - if length > max_indexes.1 - max_indexes.0 { max_indexes = (start, end + 1); } - } - return String::from(&s[max_indexes.0..max_indexes.1]); -} diff --git a/src/bin/6_zigzag_conversion.rs b/src/bin/6_zigzag_conversion.rs deleted file mode 100644 index 414175b..0000000 --- a/src/bin/6_zigzag_conversion.rs +++ /dev/null @@ -1,20 +0,0 @@ -fn main() { - println!("{}", convert(String::from("ABC"), 4)) -} - -pub fn convert(s: String, num_rows: i32) -> String { - if num_rows <= 1 { return s; } - let mut result = String::with_capacity(s.len()); - let num_rows = num_rows as usize; - for i in 0..num_rows { - for j in (i..s.len()).step_by(num_rows * 2 - 2) { - result.push(s.as_bytes()[j] as char); - if i > 0 && i < num_rows - 1 { - let diagonal_index = j + 2 * (num_rows - i - 1); - if diagonal_index >= s.len() { continue; } - result.push(s.as_bytes()[diagonal_index] as char); - } - } - } - return result; -} diff --git a/src/bin/7_reverse_integer.rs b/src/bin/7_reverse_integer.rs deleted file mode 100644 index 4a9713f..0000000 --- a/src/bin/7_reverse_integer.rs +++ /dev/null @@ -1,19 +0,0 @@ -fn main() { - println!("{}", reverse(1534236469)); -} - -// problem doesn't allow using 64-bit numbers -pub fn reverse(x: i32) -> i32 { - let is_negative = x < 0; - let (mut x, mut result) = (x.checked_abs().unwrap_or(0), 0i32); - while x > 9 { - result *= 10; - result += x % 10; - x /= 10; - } - return result.checked_mul(10).and_then(|mut n| { - n += x % 10; - if is_negative { n = -n; } - Some(n) - }).unwrap_or(0); -} diff --git a/src/bin/8_string_to_integer.rs b/src/bin/8_string_to_integer.rs deleted file mode 100644 index 673a183..0000000 --- a/src/bin/8_string_to_integer.rs +++ /dev/null @@ -1,21 +0,0 @@ -fn main() { - println!("{}", my_atoi(String::from("2147483648"))); -} - -pub fn my_atoi(s: String) -> i32 { - let s = s.trim(); - let is_neg = s.starts_with('-'); - let skip_sign = if is_neg || s.starts_with('+') { 1 } else { 0 }; - let mut result = 0i32; - for byte in s.bytes().skip(skip_sign) { - if byte < b'0' || byte > b'9' { break; } - let digit = (byte - b'0') as i32; - if let Some(checked_result) = result.checked_mul(10).and_then(|n| n.checked_add(digit)) { - result = checked_result; - } else { - return if is_neg { i32::MIN } else { i32::MAX }; - } - } - if is_neg { result = -result; } - return result; -} diff --git a/src/bin/9_palindrome_number.rs b/src/bin/9_palindrome_number.rs deleted file mode 100644 index a5b717e..0000000 --- a/src/bin/9_palindrome_number.rs +++ /dev/null @@ -1,14 +0,0 @@ -fn main() { - -} - -pub fn is_palindrome(x: i32) -> bool { - if x < 0 { return false; } - let (mut x_copy, mut reversed) = (x as u32, 0u32); - while x_copy > 0 { - reversed *= 10; - reversed += x_copy % 10; - x_copy /= 10; - } - return reversed == x as u32; -} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..4a2f141 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,16 @@ +pub mod p1_two_sum; +pub mod p2_add_two_numbers; +pub mod p3_longest_substring_without_repeating_characters; +pub mod p4_median_of_two_sorted_arrays; +pub mod p5_longest_palindrome_substring; +pub mod p6_zigzag_conversion; +pub mod p7_reverse_integer; +pub mod p8_string_to_integer; +pub mod p9_palindrome_number; +pub mod p10_regular_expression_matching; +pub mod p11_container_with_most_water; +pub mod p12_integer_to_roman; +pub mod p13_roman_to_integer; +pub mod p14_longest_common_prefix; +pub mod p15_3sum; +pub mod p16_3sum_closest; diff --git a/src/p10_regular_expression_matching.rs b/src/p10_regular_expression_matching.rs new file mode 100644 index 0000000..15a54d7 --- /dev/null +++ b/src/p10_regular_expression_matching.rs @@ -0,0 +1,34 @@ +pub struct Solution; +impl Solution { + pub fn is_match(s: String, p: String) -> bool { + let (s, p) = (s.as_bytes(), p.as_bytes()); + let mut dp = vec![vec![false; p.len() + 1]; s.len() + 1]; + dp[s.len()][p.len()] = true; + for i in (0..=s.len()).rev() { + for j in (0..p.len()).rev() { + let first_match = i < s.len() && (p[j] == b'.' || p[j] == s[i]); + if j + 1 < p.len() && p[j + 1] == b'*' { + dp[i][j] = first_match && dp[i + 1][j] || dp[i][j + 2]; + continue; + } + dp[i][j] = first_match && dp[i + 1][j + 1]; + } + } + return dp[0][0]; + } +} + +#[test] +fn test1() { + assert_eq!(Solution::is_match("aa".to_string(), "a".to_string()), false); +} + +#[test] +fn test2() { + assert_eq!(Solution::is_match("aa".to_string(), "a*".to_string()), true); +} + +#[test] +fn test3() { + assert_eq!(Solution::is_match("ab".to_string(), ".*".to_string()), true); +} diff --git a/src/p11_container_with_most_water.rs b/src/p11_container_with_most_water.rs new file mode 100644 index 0000000..8d0a4d8 --- /dev/null +++ b/src/p11_container_with_most_water.rs @@ -0,0 +1,29 @@ +pub struct Solution; +impl Solution { + pub fn max_area(height: Vec) -> i32 { + let (mut left, mut right) = (0, height.len() - 1); + let mut max_water = 0; + while left < right { + let x = (right - left) as i32; let h; + if height[left] < height[right] { + h = height[left]; + left += 1; + } else { + h = height[right]; + right -= 1; + }; + max_water = max_water.max(h * x); + } + return max_water; + } +} + +#[test] +fn test1() { + assert_eq!(Solution::max_area(vec![1,8,6,2,5,4,8,3,7]), 49); +} + +#[test] +fn test2() { + assert_eq!(Solution::max_area(vec![1,1]), 1); +} diff --git a/src/p12_integer_to_roman.rs b/src/p12_integer_to_roman.rs new file mode 100644 index 0000000..2ef0a4f --- /dev/null +++ b/src/p12_integer_to_roman.rs @@ -0,0 +1,49 @@ +pub struct Solution; +impl Solution { + pub fn int_to_roman(num: i32) -> String { + let roman_nums = vec!['M', 'D', 'C', 'L', 'X', 'V', 'I']; + let mut result = String::with_capacity(15); + let (mut num, mut divisor) = (num, 1000); + for i in (0..roman_nums.len()).step_by(2) { + let roman = roman_nums[i]; + let roman_amount = num / divisor; + match roman_amount { + 0 => (), + 1..=3 => { + for _ in 0..roman_amount { result.push(roman); } + }, + 5..=8 => { + let complement = roman_nums[i - 1]; + result.push(complement); + for _ in 0..(roman_amount-5) { result.push(roman); } + }, + 4 | 9 => { + let complement_index = i - roman_amount as usize / 4; + let complement = roman_nums[complement_index]; + result.push(roman); + result.push(complement); + }, + _ => () + } + num %= divisor; + divisor /= 10; + } + if result.is_empty() { result.push('0'); } + return result; + } +} + +#[test] +fn test1() { + assert_eq!(Solution::int_to_roman(3), "III".to_string()); +} + +#[test] +fn test2() { + assert_eq!(Solution::int_to_roman(58), "LVIII".to_string()); +} + +#[test] +fn test3() { + assert_eq!(Solution::int_to_roman(1994), "MCMXCIV".to_string()); +} diff --git a/src/p13_roman_to_integer.rs b/src/p13_roman_to_integer.rs new file mode 100644 index 0000000..2553427 --- /dev/null +++ b/src/p13_roman_to_integer.rs @@ -0,0 +1,27 @@ +pub struct Solution; +impl Solution { + pub fn roman_to_int(s: String) -> i32 { + s.chars().fold(0, |acc, c| { + let num = match c { + 'M' => 1000, 'D' => 500, 'C' => 100, 'L' => 50, + 'X' => 10, 'V' => 5, 'I' => 1, _ => 0 + }; + acc + num - 2 * (acc % num) + }) + } +} + +#[test] +fn test1() { + assert_eq!(Solution::roman_to_int("III".to_string()), 3); +} + +#[test] +fn test2() { + assert_eq!(Solution::roman_to_int("LVIII".to_string()), 58); +} + +#[test] +fn test3() { + assert_eq!(Solution::roman_to_int("MCMXCIV".to_string()), 1994); +} diff --git a/src/p14_longest_common_prefix.rs b/src/p14_longest_common_prefix.rs new file mode 100644 index 0000000..e2f3147 --- /dev/null +++ b/src/p14_longest_common_prefix.rs @@ -0,0 +1,30 @@ +pub struct Solution; +impl Solution { + pub fn longest_common_prefix(strs: Vec) -> String { + let mut result = String::with_capacity(200); + let first_str = strs[0].as_bytes(); + if first_str.is_empty() { return result; } + for i in 0..first_str.len() { + let c = first_str[i]; + for j in 1..strs.len() { + if i >= strs[j].len() || c != strs[j].as_bytes()[i] { + return result; + } + } + result.push(c as char); + } + return result; + } +} + +#[test] +fn test1() { + let strs = vec!["flower".to_string(),"flow".to_string(),"flight".to_string()]; + assert_eq!(Solution::longest_common_prefix(strs), "fl".to_string()); +} + +#[test] +fn test2() { + let strs = vec!["dog".to_string(),"racecar".to_string(),"car".to_string()]; + assert_eq!(Solution::longest_common_prefix(strs), "".to_string()); +} diff --git a/src/p15_3sum.rs b/src/p15_3sum.rs new file mode 100644 index 0000000..8858ff4 --- /dev/null +++ b/src/p15_3sum.rs @@ -0,0 +1,43 @@ +pub struct Solution; +impl Solution { + pub fn three_sum(mut nums: Vec) -> Vec> { + let mut result = Vec::>::new(); + nums.sort(); + for i in 0..nums.len()-2 { + if i > 0 && nums[i] == nums[i - 1] { continue; } + let (mut j, mut k) = (i + 1, nums.len() - 1); + while j < k { + if j > i + 1 && nums[j - 1] == nums[j] { + j += 1; continue; + } + if k < nums.len() - 1 && nums[k + 1] == nums[k] { + k -= 1; continue; + } + match (nums[i] + nums[j] + nums[k]).cmp(&0) { + std::cmp::Ordering::Less => { j += 1; }, + std::cmp::Ordering::Greater => { k -= 1 }, + std::cmp::Ordering::Equal => { + result.push(vec![nums[i], nums[j], nums[k]]); + j += 1; k -= 1; + } + } + } + } + return result; + } +} + +#[test] +fn test1() { + assert_eq!(Solution::three_sum(vec![-1,0,1,2,-1,-4]), vec![vec![-1,-1,2], vec![-1,0,1]]); +} + +#[test] +fn test2() { + assert_eq!(Solution::three_sum(vec![0,1,1]), Vec::>::new()); +} + +#[test] +fn test3() { + assert_eq!(Solution::three_sum(vec![0,0,0]), vec![vec![0,0,0]]); +} \ No newline at end of file diff --git a/src/p16_3sum_closest.rs b/src/p16_3sum_closest.rs new file mode 100644 index 0000000..c16a072 --- /dev/null +++ b/src/p16_3sum_closest.rs @@ -0,0 +1,17 @@ +pub struct Solution; +impl Solution { + pub fn three_sum_closest(nums: Vec, target: i32) -> i32 { + + return 0; + } +} + +#[test] +fn test1() { + assert_eq!(Solution::three_sum_closest(vec![-1,2,1,-4], 1), 2); +} + +#[test] +fn test2() { + assert_eq!(Solution::three_sum_closest(vec![0,0,0], 1), 0); +} diff --git a/src/p1_two_sum.rs b/src/p1_two_sum.rs new file mode 100644 index 0000000..2b3d484 --- /dev/null +++ b/src/p1_two_sum.rs @@ -0,0 +1,35 @@ +use std::collections::HashMap; + +pub struct Solution; +impl Solution { + pub fn two_sum(nums: Vec, target: i32) -> Vec { + let mut components: HashMap = HashMap::new(); + for i in 0..nums.len() { + let component = target - nums[i]; + if let Some(j) = components.get(&component) { + return vec![i as i32, *j as i32]; + } + components.insert(nums[i], i); + } + return Vec::new(); + } +} + +#[test] +fn test1() { + let actual = Solution::two_sum(vec![2,7,11,15], 9); + assert!(actual == vec![1,0] || actual == vec![0,1]); +} + +#[test] +fn test2() { + let actual = Solution::two_sum(vec![3,2,4], 6); + assert!(actual == vec![1,2] || actual == vec![2,1]); +} + +#[test] +fn test3() { + let actual = Solution::two_sum(vec![3,3], 6); + assert!(actual == vec![1,0] || actual == vec![0,1]); +} + \ No newline at end of file diff --git a/src/p2_add_two_numbers.rs b/src/p2_add_two_numbers.rs new file mode 100644 index 0000000..25b80c3 --- /dev/null +++ b/src/p2_add_two_numbers.rs @@ -0,0 +1,50 @@ +pub struct Solution; +impl Solution { + pub fn add_two_numbers(l1: Option>, l2: Option>) -> Option> { + let (mut l1, mut l2) = (l1, l2); + let mut head = Box::new(ListNode::new(0)); + let mut tail = &mut head; + loop { + let mut sum = tail.val; + if let Some(node) = &l1 { + sum += node.val; + l1 = node.next.clone(); + } + if let Some(node) = &l2 { + sum += node.val; + l2 = node.next.clone(); + } + let next_node = Box::new(ListNode::new(sum / 10)); + tail.val = sum % 10; + if l1.is_none() && l2.is_none() { + if next_node.val > 0 { tail.next = Some(next_node); } + break; + } + tail.next = Some(next_node); + tail = tail.next.as_mut().unwrap(); + } + return Some(head); + } +} + +// Definition for singly-linked list. +#[derive(PartialEq, Eq, Clone, Debug)] +pub struct ListNode { + pub val: i32, + pub next: Option> +} + +impl ListNode { + #[inline] + fn new(val: i32) -> Self { + ListNode { + next: None, + val + } + } +} + +#[test] +fn test() { + +} diff --git a/src/p3_longest_substring_without_repeating_characters.rs b/src/p3_longest_substring_without_repeating_characters.rs new file mode 100644 index 0000000..3c48887 --- /dev/null +++ b/src/p3_longest_substring_without_repeating_characters.rs @@ -0,0 +1,34 @@ +use std::collections::HashMap; + +pub struct Solution; +impl Solution { + pub fn length_of_longest_substring(s: String) -> i32 { + let mut seen: HashMap = HashMap::with_capacity(80); + let (mut start_index, mut max_length) = (0usize, 0usize); + for (i, c) in s.chars().enumerate() { + if let Some(index) = seen.get(&c) { + max_length = max_length.max(i - start_index); + start_index = *index + 1; + seen.retain(|_, i| *i >= start_index); + } + seen.insert(c, i); + } + max_length = max_length.max(s.len() - start_index); + return max_length as i32; + } +} + +#[test] +fn test1() { + assert_eq!(Solution::length_of_longest_substring("abcabcbb".to_string()), 3); +} + +#[test] +fn test2() { + assert_eq!(Solution::length_of_longest_substring("bbbbb".to_string()), 1); +} + +#[test] +fn test3() { + assert_eq!(Solution::length_of_longest_substring("pwwkew".to_string()), 3); +} diff --git a/src/p4_median_of_two_sorted_arrays.rs b/src/p4_median_of_two_sorted_arrays.rs new file mode 100644 index 0000000..4a7189f --- /dev/null +++ b/src/p4_median_of_two_sorted_arrays.rs @@ -0,0 +1,31 @@ +pub struct Solution; +impl Solution { + // TODO: reduce algorithm complexity from O(m+n) to O(log(m+n)) + pub fn find_median_sorted_arrays(nums1: Vec, nums2: Vec) -> f64 { + let length = nums1.len() + nums2.len(); + let mut nums3 = vec![0i32; length]; + let (mut m, mut n) = (0usize, 0usize); + while m + n < length { + let x1 = if m < nums1.len() { nums1[m] } else { i32::MAX }; + let x2 = if n < nums2.len() { nums2[n] } else { i32::MAX }; + if x1 <= x2 { + nums3[m + n] = x1; + m += 1; + } else { + nums3[m + n] = x2; + n += 1; + } + } + return (nums3[(length - 1) / 2] + nums3[length / 2]) as f64 / 2.0; + } +} + +#[test] +fn test1() { + assert_eq!(Solution::find_median_sorted_arrays(vec![1,3], vec![2]), 2.0); +} + +#[test] +fn test2() { + assert_eq!(Solution::find_median_sorted_arrays(vec![1,2], vec![3,4]), 2.5); +} diff --git a/src/p5_longest_palindrome_substring.rs b/src/p5_longest_palindrome_substring.rs new file mode 100644 index 0000000..04a7342 --- /dev/null +++ b/src/p5_longest_palindrome_substring.rs @@ -0,0 +1,27 @@ +pub struct Solution; +impl Solution { + pub fn longest_palindrome(s: String) -> String { + let mut max_indexes = (0usize, 1usize); + for i in 0..(s.len()-1)*2 { + let (mut start, mut end) = (i / 2 + i % 2, i / 2); + while start > 0 && end < s.len() - 1 { + if s.as_bytes()[start - 1] != s.as_bytes()[end + 1] { break; } + start -= 1; end += 1; + } + let length = end + 1 - start; + if length > max_indexes.1 - max_indexes.0 { max_indexes = (start, end + 1); } + } + return String::from(&s[max_indexes.0..max_indexes.1]); + } +} + +#[test] +fn test1() { + let actual = Solution::longest_palindrome("babad".to_string()); + assert!(actual == "bab".to_string() || actual == "aba".to_string()); +} + +#[test] +fn test2() { + assert_eq!(Solution::longest_palindrome("cbbd".to_string()), "bb".to_string()); +} diff --git a/src/p6_zigzag_conversion.rs b/src/p6_zigzag_conversion.rs new file mode 100644 index 0000000..1946c6e --- /dev/null +++ b/src/p6_zigzag_conversion.rs @@ -0,0 +1,34 @@ +pub struct Solution; +impl Solution { + pub fn convert(s: String, num_rows: i32) -> String { + if num_rows <= 1 { return s; } + let mut result = String::with_capacity(s.len()); + let num_rows = num_rows as usize; + for i in 0..num_rows { + for j in (i..s.len()).step_by(num_rows * 2 - 2) { + result.push(s.as_bytes()[j] as char); + if i > 0 && i < num_rows - 1 { + let diagonal_index = j + 2 * (num_rows - i - 1); + if diagonal_index >= s.len() { continue; } + result.push(s.as_bytes()[diagonal_index] as char); + } + } + } + return result; + } +} + +#[test] +fn test1() { + assert_eq!(Solution::convert("PAYPALISHIRING".to_string(), 3), "PAHNAPLSIIGYIR".to_string()); +} + +#[test] +fn test2() { + assert_eq!(Solution::convert("PAYPALISHIRING".to_string(), 4), "PINALSIGYAHRPI".to_string()); +} + +#[test] +fn test3() { + assert_eq!(Solution::convert("A".to_string(), 1), "A".to_string()); +} diff --git a/src/p7_reverse_integer.rs b/src/p7_reverse_integer.rs new file mode 100644 index 0000000..e4d752b --- /dev/null +++ b/src/p7_reverse_integer.rs @@ -0,0 +1,33 @@ +pub struct Solution; +impl Solution { + // problem doesn't allow using 64-bit numbers + pub fn reverse(x: i32) -> i32 { + let is_negative = x < 0; + let (mut x, mut result) = (x.checked_abs().unwrap_or(0), 0i32); + while x > 9 { + result *= 10; + result += x % 10; + x /= 10; + } + return result.checked_mul(10).and_then(|mut n| { + n += x % 10; + if is_negative { n = -n; } + Some(n) + }).unwrap_or(0); + } +} + +#[test] +fn test1() { + assert_eq!(Solution::reverse(123), 321); +} + +#[test] +fn test2() { + assert_eq!(Solution::reverse(-123), -321); +} + +#[test] +fn test3() { + assert_eq!(Solution::reverse(120), 21); +} diff --git a/src/p8_string_to_integer.rs b/src/p8_string_to_integer.rs new file mode 100644 index 0000000..9b0f433 --- /dev/null +++ b/src/p8_string_to_integer.rs @@ -0,0 +1,35 @@ +pub struct Solution; +impl Solution { + pub fn my_atoi(s: String) -> i32 { + let s = s.trim(); + let is_neg = s.starts_with('-'); + let skip_sign = if is_neg || s.starts_with('+') { 1 } else { 0 }; + let mut result = 0i32; + for byte in s.bytes().skip(skip_sign) { + if byte < b'0' || byte > b'9' { break; } + let digit = (byte - b'0') as i32; + if let Some(checked_result) = result.checked_mul(10).and_then(|n| n.checked_add(digit)) { + result = checked_result; + } else { + return if is_neg { i32::MIN } else { i32::MAX }; + } + } + if is_neg { result = -result; } + return result; + } +} + +#[test] +fn test1() { + assert_eq!(Solution::my_atoi("42".to_string()), 42); +} + +#[test] +fn test2() { + assert_eq!(Solution::my_atoi(" -42".to_string()), -42); +} + +#[test] +fn test3() { + assert_eq!(Solution::my_atoi("4193 with words".to_string()), 4193); +} diff --git a/src/p9_palindrome_number.rs b/src/p9_palindrome_number.rs new file mode 100644 index 0000000..b95e9ca --- /dev/null +++ b/src/p9_palindrome_number.rs @@ -0,0 +1,28 @@ +pub struct Solution; +impl Solution { + pub fn is_palindrome(x: i32) -> bool { + if x < 0 { return false; } + let (mut x_copy, mut reversed) = (x as u32, 0u32); + while x_copy > 0 { + reversed *= 10; + reversed += x_copy % 10; + x_copy /= 10; + } + return reversed == x as u32; + } +} + +#[test] +fn test1() { + assert_eq!(Solution::is_palindrome(121), true); +} + +#[test] +fn test2() { + assert_eq!(Solution::is_palindrome(-121), false); +} + +#[test] +fn test3() { + assert_eq!(Solution::is_palindrome(10), false); +}