Skip to content

Commit

Permalink
Add problem 2227: Encrypt and Decrypt Strings
Browse files Browse the repository at this point in the history
  • Loading branch information
EFanZh committed Oct 28, 2024
1 parent eeab2f9 commit e13c5c6
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1662,6 +1662,7 @@ pub mod problem_2222_number_of_ways_to_select_buildings;
pub mod problem_2224_minimum_number_of_operations_to_convert_time;
pub mod problem_2225_find_players_with_zero_or_one_losses;
pub mod problem_2226_maximum_candies_allocated_to_k_children;
pub mod problem_2227_encrypt_and_decrypt_strings;
pub mod problem_2231_largest_number_after_digit_swaps_by_parity;
pub mod problem_2232_minimize_result_by_adding_parentheses_to_expression;
pub mod problem_2233_maximum_product_after_k_increments;
Expand Down
85 changes: 85 additions & 0 deletions src/problem_2227_encrypt_and_decrypt_strings/hash_map.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// ------------------------------------------------------ snip ------------------------------------------------------ //

use std::collections::hash_map::Entry;
use std::collections::HashMap;

pub struct Encrypter {
encryption_map: [[u8; 2]; 26],
encrypted_dictionary: HashMap<Box<[u8]>, u8>,
}

impl Encrypter {
fn new(keys: Vec<char>, values: Vec<String>, dictionary: Vec<String>) -> Self {
let mut encryption_map = [[u8::MAX; 2]; 26];

keys.into_iter().zip(values).for_each(|(key, value)| {
encryption_map[key as usize - usize::from(b'a')] = value.into_bytes().try_into().ok().unwrap();
});

let mut encrypted_dictionary = HashMap::with_capacity(dictionary.len());

for word in dictionary {
let encrypted_word = Self::encrypt_impl(&encryption_map, word);

if !encrypted_word.is_empty() {
match encrypted_dictionary.entry(encrypted_word.into_bytes().into_boxed_slice()) {
Entry::Occupied(occupied_entry) => *occupied_entry.into_mut() += 1,
Entry::Vacant(vacant_entry) => {
vacant_entry.insert(1);
}
}
}
}

Self {
encryption_map,
encrypted_dictionary,
}
}

fn encrypt_impl(encryption_map: &[[u8; 2]; 26], word: String) -> String {
String::from_utf8(
word.into_bytes()
.into_iter()
.flat_map(|c| encryption_map[usize::from(c) - usize::from(b'a')])
.collect(),
)
.unwrap_or_default()
}

fn encrypt(&self, word1: String) -> String {
Self::encrypt_impl(&self.encryption_map, word1)
}

fn decrypt(&self, word2: String) -> i32 {
self.encrypted_dictionary
.get(word2.as_bytes())
.copied()
.unwrap_or(0)
.into()
}
}

// ------------------------------------------------------ snip ------------------------------------------------------ //

impl super::Encrypter for Encrypter {
fn new(keys: Vec<char>, values: Vec<String>, dictionary: Vec<String>) -> Self {
Self::new(keys, values, dictionary)
}

fn encrypt(&self, word1: String) -> String {
self.encrypt(word1)
}

fn decrypt(&self, word2: String) -> i32 {
self.decrypt(word2)
}
}

#[cfg(test)]
mod tests {
#[test]
fn test_solution() {
super::super::tests::run::<super::Encrypter>();
}
}
52 changes: 52 additions & 0 deletions src/problem_2227_encrypt_and_decrypt_strings/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
pub mod hash_map;

pub trait Encrypter {
fn new(keys: Vec<char>, values: Vec<String>, dictionary: Vec<String>) -> Self;
fn encrypt(&self, word1: String) -> String;
fn decrypt(&self, word2: String) -> i32;
}

#[cfg(test)]
mod tests {
use super::Encrypter;

enum Operation {
Encrypt(&'static str, &'static str),
Decrypt(&'static str, i32),
}

pub fn run<E: Encrypter>() {
let test_cases = [
(
(
"abcd",
&["ei", "zf", "ei", "am"] as &[_],
&["abcd", "acbd", "adbc", "badc", "dacb", "cadb", "cbda", "abad"] as &[_],
),
&[
Operation::Encrypt("abcd", "eizfeiam"),
Operation::Decrypt("eizfeiam", 2),
] as &[_],
),
(
("b", &["ca"], &["aaa", "cacbc", "bbaba", "bb"]),
&[Operation::Encrypt("bbb", "cacaca"), Operation::Decrypt("cacaca", 0)],
),
];

for ((keys, values, dictionary), operations) in test_cases {
let encrypter = E::new(
keys.chars().collect(),
values.iter().copied().map(str::to_string).collect(),
dictionary.iter().copied().map(str::to_string).collect(),
);

for operation in operations {
match *operation {
Operation::Encrypt(word1, expected) => assert_eq!(encrypter.encrypt(word1.to_string()), expected),
Operation::Decrypt(word2, expected) => assert_eq!(encrypter.decrypt(word2.to_string()), expected),
}
}
}
}
}

0 comments on commit e13c5c6

Please sign in to comment.