From 39c3fae613a3c51dcf0a7aa180833aaae03976c4 Mon Sep 17 00:00:00 2001 From: BoolPurist Date: Tue, 6 Aug 2024 10:01:55 +0200 Subject: [PATCH] Solved game jump from leet code --- .gitignore | 1 + Cargo.lock | 7 +++ Cargo.toml | 6 +++ src/lib.rs | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 3 ++ 5 files changed, 140 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/lib.rs create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..334f8df --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "jump_game" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..0557a5e --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "jump_game" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..98abc21 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,123 @@ +struct Solution; + +// Copy from here for submitting this solution to leet code +impl Solution { + pub fn can_jump(nums: Vec) -> bool { + Solution::idiom_can_jump(&nums) + } + + /// + /// ## Mapping elements to nodes in a graph + /// Every index is viewed as a node in a graph. + /// The value of a node (value of the element in the array) + /// is the number of edges to subsequent successors. + /// + /// ### Example + /// Given the first element in \[3,2,1,0,4\] + /// + /// This element has two edges, with the second and the third elements as subsequent successors + /// + /// ## Why the mapping to a graph + /// + /// By doing so, one can skip redundant work. + /// Redundant work would be walking a path more than once. + /// Walking a path is simulating jumping from 1 to the max jump height. + /// Path walking checks if any jump height from a certain index will reach the last index. + /// Every simulated jump height serves as a next start point for new path walking if this starting + /// point was not tried before + pub fn idiom_can_jump(nums: &[i32]) -> bool { + if nums.is_empty() { + return false; + } + let target_val = (nums.len() - 1) as i32; + let mut next_nodes = Vec::from([(0, nums[0])]); + // index visited yet + let mut visted_indices = -1; + if Self::check_with_target_value(target_val, 0) { + return true; + } + while let Some(next_node) = next_nodes.pop() { + let (index, steps) = next_node; + let max_jump_height = index + steps; + if Self::check_with_target_value(target_val, max_jump_height) { + return true; + } + // It can start at 1 because the every index was checked in previous path walking + for next_to_check in 1..=steps { + let to_add = index + next_to_check; + if visted_indices >= to_add { + // already visited this index + continue; + } + visted_indices = to_add; + next_nodes.push((to_add, nums[to_add as usize])); + } + } + false + } + fn check_with_target_value(target: i32, value: i32) -> bool { + target <= value + } +} +// Stop copying from here for submitting this solution to leet code + +#[cfg(test)] +mod testing { + use crate::Solution; + + #[test] + fn empty_input() { + let given = vec![]; + let expected = false; + assert_case(given, expected); + } + + #[test] + fn jumping_no_matter_because_one_element() { + let given = vec![0]; + let expected = true; + assert_case(given, expected); + } + + #[test] + //Input: nums = [2,3,1,1,4] + //Output: true + //Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index. + fn jump_possible() { + // Example 1: + // + let given = vec![2, 3, 1, 1, 4]; + let expected = true; + assert_case(given, expected); + } + + //Example 2: + // + //Input: nums = [3,2,1,0,4] + //Output: false + #[test] + fn no_jump_possible() { + let given = vec![3, 2, 1, 0, 4]; + let expected = false; + assert_case(given, expected); + } + + #[test] + fn jump_two_elements() { + let given = vec![2, 0]; + let expected = true; + assert_case(given, expected); + } + + #[test] + fn can_jump_complex_array() { + let given = vec![3, 0, 8, 2, 0, 0, 1]; + let expected = true; + assert_case(given, expected); + } + + fn assert_case(given: Vec, expected: bool) { + let actual = Solution::idiom_can_jump(&given); + assert_eq!(expected, actual, "Given input: {:#?}", &given); + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +}