diff --git a/.gitignore b/.gitignore index b30a728..d05f038 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *.o bin +target diff --git a/problems/8-string-to-integer/Cargo.lock b/problems/8-string-to-integer/Cargo.lock new file mode 100644 index 0000000..dfef985 --- /dev/null +++ b/problems/8-string-to-integer/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "string-to-integer" +version = "0.1.0" diff --git a/problems/8-string-to-integer/Cargo.toml b/problems/8-string-to-integer/Cargo.toml new file mode 100644 index 0000000..495f31d --- /dev/null +++ b/problems/8-string-to-integer/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "string-to-integer" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/problems/8-string-to-integer/src/lib.rs b/problems/8-string-to-integer/src/lib.rs new file mode 100644 index 0000000..4320ea6 --- /dev/null +++ b/problems/8-string-to-integer/src/lib.rs @@ -0,0 +1,148 @@ +use std::convert::TryInto; + +pub struct Solution{} + +impl Solution { + pub fn my_atoi(s: String) -> i32 { + let mut res: i32 = 0; + let mut sign: i32 = 1; + let mut sign_was_scanned = false; + let mut digit_was_scanned = false; + + for c in s.chars() { + if c >= '0' && c <= '9' { + digit_was_scanned = true; + let conv: i32 = c.to_digit(10).unwrap().try_into().unwrap(); + // Test overflow + if sign > 0 && res > (i32::MAX - conv * sign) / 10 { + return i32::MAX; + } + if sign < 0 && res < (i32::MIN - conv * sign) / 10 { + return i32::MIN; + } + // Add new digit + res = res * 10 + conv * sign; + } + // First '-' + else if c == '-' && sign_was_scanned == false && digit_was_scanned == false { + sign_was_scanned = true; + sign *= -1; + } + // Repeated '-' or '-' after number + else if c == '-' { + return res; + } + // First '+' + else if c == '+' && sign_was_scanned == false && digit_was_scanned == false { + sign_was_scanned = true; + } + // Repeated '+' or '+' after number + else if c == '+' { + return res; + } + // Letters before number + else if c != '+' && c != ' ' && digit_was_scanned == false { + return 0; + } + // Space after sign + else if c == ' ' && sign_was_scanned { + return res; + } + // Letters after number + else if digit_was_scanned == true { + return res; + } + } + + return res; + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_simple_string() { + let input = String::from("42"); + let result = Solution::my_atoi(input); + assert_eq!(result, 42); + } + + #[test] + fn test_spaces() { + let input = String::from(" -42"); + let result = Solution::my_atoi(input); + assert_eq!(result, -42); + } + + #[test] + fn test_words() { + let input = String::from("4193 with words"); + let result = Solution::my_atoi(input); + assert_eq!(result, 4193); + } + + #[test] + fn test_zeros() { + let input = String::from("0032"); + let result = Solution::my_atoi(input); + assert_eq!(result, 32); + } + + #[test] + fn test_max_int() { + let input = String::from("21474242483648"); + let result = Solution::my_atoi(input); + assert_eq!(result, i32::MAX); + } + + #[test] + fn test_min_int() { + let input = String::from("-2424147483649"); + let result = Solution::my_atoi(input); + assert_eq!(result, i32::MIN); + } + + #[test] + fn test_invalid_string() { + let input = String::from("words and 987"); + let result = Solution::my_atoi(input); + assert_eq!(result, 0); + } + + #[test] + fn test_garbage_after_number() { + let input = String::from("3.14159"); + let result = Solution::my_atoi(input); + assert_eq!(result, 3); + } + + #[test] + fn test_multiple_signs() { + let input = String::from("+-12"); + let result = Solution::my_atoi(input); + assert_eq!(result, 0); + } + + #[test] + fn test_sign_after_number() { + let input = String::from("00000-42a1234"); + let result = Solution::my_atoi(input); + assert_eq!(result, 0); + } + + #[test] + fn test_minus_after_negative_number() { + let input = String::from("-5-"); + let result = Solution::my_atoi(input); + assert_eq!(result, -5); + } + + #[test] + fn test_space_after_sign() { + let input = String::from(" + 413"); + let result = Solution::my_atoi(input); + assert_eq!(result, 0); + } +} diff --git a/readme.md b/readme.md index d5f0e3d..753afc0 100644 --- a/readme.md +++ b/readme.md @@ -6,15 +6,26 @@ For programs written in C: -``` +```bash cd problems/random-problem make make run ``` +For programs written in Rust: + +```bash +cd problems/random-problem +cargo test +``` + ## Solution structure For programs written in C: - `lib.c` - the solution itself - `main.c` - tests + +For programs written in Rust: + +- `src/lib.rs` - solution and tests