|
| 1 | +//! This module provides functionality to determine whether two strings are isomorphic. |
| 2 | +//! |
| 3 | +//! Two strings are considered isomorphic if the characters in one string can be replaced |
| 4 | +//! by some mapping relation to obtain the other string. |
| 5 | +use std::collections::HashMap; |
| 6 | + |
| 7 | +/// Determines whether two strings are isomorphic. |
| 8 | +/// |
| 9 | +/// # Arguments |
| 10 | +/// |
| 11 | +/// * `s` - The first string. |
| 12 | +/// * `t` - The second string. |
| 13 | +/// |
| 14 | +/// # Returns |
| 15 | +/// |
| 16 | +/// `true` if the strings are isomorphic, `false` otherwise. |
| 17 | +pub fn is_isomorphic(s: &str, t: &str) -> bool { |
| 18 | + let s_chars: Vec<char> = s.chars().collect(); |
| 19 | + let t_chars: Vec<char> = t.chars().collect(); |
| 20 | + if s_chars.len() != t_chars.len() { |
| 21 | + return false; |
| 22 | + } |
| 23 | + let mut s_to_t_map = HashMap::new(); |
| 24 | + let mut t_to_s_map = HashMap::new(); |
| 25 | + for (s_char, t_char) in s_chars.into_iter().zip(t_chars) { |
| 26 | + if !check_mapping(&mut s_to_t_map, s_char, t_char) |
| 27 | + || !check_mapping(&mut t_to_s_map, t_char, s_char) |
| 28 | + { |
| 29 | + return false; |
| 30 | + } |
| 31 | + } |
| 32 | + true |
| 33 | +} |
| 34 | + |
| 35 | +/// Checks the mapping between two characters and updates the map. |
| 36 | +/// |
| 37 | +/// # Arguments |
| 38 | +/// |
| 39 | +/// * `map` - The HashMap to store the mapping. |
| 40 | +/// * `key` - The key character. |
| 41 | +/// * `value` - The value character. |
| 42 | +/// |
| 43 | +/// # Returns |
| 44 | +/// |
| 45 | +/// `true` if the mapping is consistent, `false` otherwise. |
| 46 | +fn check_mapping(map: &mut HashMap<char, char>, key: char, value: char) -> bool { |
| 47 | + match map.get(&key) { |
| 48 | + Some(&mapped_char) => mapped_char == value, |
| 49 | + None => { |
| 50 | + map.insert(key, value); |
| 51 | + true |
| 52 | + } |
| 53 | + } |
| 54 | +} |
| 55 | + |
| 56 | +#[cfg(test)] |
| 57 | +mod tests { |
| 58 | + use super::is_isomorphic; |
| 59 | + macro_rules! test_is_isomorphic { |
| 60 | + ($($name:ident: $inputs:expr,)*) => { |
| 61 | + $( |
| 62 | + #[test] |
| 63 | + fn $name() { |
| 64 | + let (s, t, expected) = $inputs; |
| 65 | + assert_eq!(is_isomorphic(s, t), expected); |
| 66 | + assert_eq!(is_isomorphic(t, s), expected); |
| 67 | + assert!(is_isomorphic(s, s)); |
| 68 | + assert!(is_isomorphic(t, t)); |
| 69 | + } |
| 70 | + )* |
| 71 | + } |
| 72 | + } |
| 73 | + test_is_isomorphic! { |
| 74 | + isomorphic: ("egg", "add", true), |
| 75 | + isomorphic_long: ("abcdaabdcdbbabababacdadad", "AbCdAAbdCdbbAbAbAbACdAdAd", true), |
| 76 | + not_isomorphic: ("egg", "adc", false), |
| 77 | + non_isomorphic_long: ("abcdaabdcdbbabababacdadad", "AACdAAbdCdbbAbAbAbACdAdAd", false), |
| 78 | + isomorphic_unicode: ("天苍苍", "野茫茫", true), |
| 79 | + isomorphic_unicode_different_byte_size: ("abb", "野茫茫", true), |
| 80 | + empty: ("", "", true), |
| 81 | + different_length: ("abc", "abcd", false), |
| 82 | + } |
| 83 | +} |
0 commit comments