diff --git a/README.md b/README.md index 64b0664..c525e5b 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ cargo test - [x] [Aho-Corasick Algorithm](./src/string/aho_corasick.rs) - [x] [Burrows-Wheeler transform](./src/string/burrows_wheeler_transform.rs) -- [ ] Finite Automaton +- [x] [Finite Automaton](./src/string/finite_automaton.rs) - [x] [Hamming Distance](./src/string/hamming_distance.rs) - [x] [Knuth Morris Pratt](./src/string/knuth_morris_pratt.rs) - [x] [Manacher](./src/string/manacher.rs) diff --git a/src/string/README.md b/src/string/README.md index b29a60c..797e10c 100644 --- a/src/string/README.md +++ b/src/string/README.md @@ -62,3 +62,8 @@ In this algorithm, we construct a Z array. __Properties__ * Case-performance = O(m + n) * Case space complexity O(w) + +### [Deterministic finite automaton](./finite_automaton.rs) +From [Wikipedia][finite-automaton-wiki]: In the theory of computation, a branch of theoretical computer science, a deterministic finite automaton (DFA)—also known as deterministic finite acceptor (DFA), deterministic finite-state machine (DFSM), or deterministic finite-state automaton (DFSA)—is a finite-state machine that accepts or rejects a given string of symbols, by running through a state sequence uniquely determined by the string. + +[finite-automaton-wiki]: https://en.wikipedia.org/wiki/Deterministic_finite_automaton diff --git a/src/string/finite_automaton.rs b/src/string/finite_automaton.rs new file mode 100644 index 0000000..3ad1725 --- /dev/null +++ b/src/string/finite_automaton.rs @@ -0,0 +1,75 @@ +#[derive(Default)] +pub struct DeterministicFiniteAutomata { + current_state: usize, + transition_matrix: Vec>, // Matrix of transitions for '0' and '1' + accept_states: Vec, // Indicates if a state is an accepting state +} + +impl DeterministicFiniteAutomata { + pub fn new() -> Self { + let transition_matrix = vec![ + vec![1, 4], // From State 0, '0' leads to State 1, '1' to State 4 + vec![2, 0], // From State 1, '0' leads to State 2, '1' to State 0 + vec![3, 1], // From State 2, '0' leads to State 3, '1' to State 1 + vec![4, 2], // From State 3, '0' leads to State 4, '1' to State 2 + vec![0, 3], // From State 4, '0' leads to State 0, '1' to State 3 + ]; + let accept_states = vec![true, false, true, false, true]; // Accepting states: 0, 2, 4 + DeterministicFiniteAutomata { + current_state: 0, + transition_matrix, + accept_states, + } + } + + pub fn process(&mut self, input: &str) -> bool { + for c in input.chars() { + if let Some(index) = c.to_digit(10) { + let index = index as usize; + // Update the current state of the DFA using the transition matrix + // The new state is determined by the current state and the input digit + self.current_state = self.transition_matrix[self.current_state][index]; + } + } + // Return whether the final state after processing the input string is an accepting state + self.accept_states[self.current_state] + } + + pub fn reset(&mut self) { + self.current_state = 0; + } +} + +#[cfg(test)] +mod tests { + use crate::string::finite_automaton::DeterministicFiniteAutomata; + + #[test] + fn test_even_zeros() { + let mut dfa = DeterministicFiniteAutomata::new(); + assert!(dfa.process("00000")); + dfa.reset(); + assert!(dfa.process("01011")); + dfa.reset(); + assert!(dfa.process("10011")); + dfa.reset(); + } + + #[test] + fn test_odd_zeros() { + let mut dfa = DeterministicFiniteAutomata::new(); + assert!(!dfa.process("0")); + dfa.reset(); + assert!(!dfa.process("000")); + dfa.reset(); + assert!(!dfa.process("01001")); + dfa.reset(); + } + + #[test] + fn test_empty_input() { + let mut dfa = DeterministicFiniteAutomata::new(); + assert!(dfa.process("")); // No moves, starts and remains at zero step + dfa.reset(); + } +} diff --git a/src/string/mod.rs b/src/string/mod.rs index 7a0aa27..2e9ad7f 100644 --- a/src/string/mod.rs +++ b/src/string/mod.rs @@ -1,5 +1,6 @@ mod aho_corasick; mod burrows_wheeler_transform; +mod finite_automaton; mod hamming_distance; mod knuth_morris_pratt; mod manacher; @@ -11,6 +12,7 @@ mod z_algorithm; pub use self::aho_corasick::AhoCorasick; pub use self::burrows_wheeler_transform::burrows_wheeler_transform; pub use self::burrows_wheeler_transform::inv_burrows_wheeler_transform; +pub use self::finite_automaton::DeterministicFiniteAutomata; pub use self::hamming_distance::hamming_distance; pub use self::knuth_morris_pratt::knuth_morris_pratt; pub use self::manacher::manacher;