Duplicate Encode Kata
Today I did few katas on codewars. One of the kata was this one.
Basically, you need to change every character in a word. If it appears multiple
times, then change it to )
, otherwise change it to (
.
What I learned is simple solution using find()
and rfind()
.
As usual, there are many approaches to solve this challenge, so let's see two of them first.
Solution 1: obvious
- create a
HashMap
and count each character occurrence - iterate via characters again, and based on its occurrence, change the character
solution 2: small improvement
It is based on simple observation that we don't actually need to count occurrence of each character. We need to know if this character already appeared in a word:
- use
HashSet
instead ofHashMap
- for each character check if it's already in a set
- if it is, then we can already change the character to
)
, otherwise add it to the set - at the end change each of the remaining characters to
(
because if those characters were not changed, that's because they were not present in the set, so those are not duplicated
the trick
Nice feature of codewars is that you can see others solutions. Moreover, you can filter them by "Clever" or by "Best practices". There was one clever solution which caused "oh!" effect.
The idea is similar to our previous solution - we don't need to count characters. But the way we determine if character is duplicated is smarter.
- For each character, run
word.find(character)
to get index of the character in a word, - But we'll find the same character we are already checking
- To fix the issue, we'll do
word.rfind(character)
- reverse search - and compare two found indices - If those indices are the same it means that there is only one such character
- Otherwise there are more
The solution is simple and clean as following:
fn duplicate_encode(word: &str) -> String {
let word = String::from(word).to_lowercase();
word.chars()
.map(|c| {
if word.find(c) == word.rfind(c) {
'('
} else {
')'
}
})
.collect()
}