We can't find the internet
Attempting to reconnect
Something went wrong!
Hang in there while we get back on track
Post 52
Hacker Rank 25 - Password Hacker
Published on: 2025-08-03
Tags:
elixir, Side Project, Hacker Rank
So for this one we are given a set of passwords and a passphrase. For this fake horribly designed site you are to give a set of passwords that will work, the site will allow for any passphrase at is any combination of the passphrases. So if the passphrases are ~w(cat dog chicken)
catdog or dogchicken or chickenchicken all would work along with many other text strings.
So for this we need to do a few things in order to find out if a phrase and set of passphrases will work for the website.
A trie is a tree where each level represents one letter of a word. It allows fast checking of whether a word or prefix exists. In our solution, we use it to walk through the loginAttempt string efficiently, checking if any prefix matches a password. If a path ends at a word, we note it and continue searching from there.
First inorder to avoid a longer set of queries we will make a trie that is short for "retrieval" tree that will create a tree for each letter of the passphrases, so ~w(cat dog) would look like
C
|- A
| |- T (:end)
|- D
|- O
|- G (:end)
This way we can check the first letter and then other letters as we get further down the tree. and avoid longer checks for the entire word.
# Build a trie from the list of passwords
defp build_trie(words) do
Enum.reduce(words, %{}, fn word, trie ->
insert_trie(String.to_charlist(word), trie)
end)
end
defp insert_trie([], trie), do: Map.put(trie, :end, true)
defp insert_trie([h | t], trie) do
Map.update(trie, h, insert_trie(t, %{}), fn subtrie ->
insert_trie(t, subtrie)
end)
end
Next is the BFS search that will keep an updated queue of the position of in the phrase and the current word list.
At each letter of the phrase we will:
If we’ve reached the end of the phrase, we return the matched word list
If the current position was already visited, skip it
Otherwise, we:
Use the trie to find all valid words starting at that position
Add new states to the queue for each of those
If the queue empties without a solution, return "WRONG PASSWORD"
# BFS search over the loginAttempt using the trie
defp bfs([phrase], trie) do
chars = String.to_charlist(phrase)
len = length(chars)
# Queue holds {position_in_phrase, current_word_list}
queue = :queue.from_list([{0, []}])
visited = MapSet.new()
bfs_loop(chars, trie, len, queue, visited)
end
defp bfs_loop(chars, trie, len, queue, visited) do
if :queue.is_empty(queue) do
:error
else
{{:value, {pos, words}}, queue} = :queue.out(queue)
if pos == len do
{:ok, words}
else
if MapSet.member?(visited, pos) do
bfs_loop(chars, trie, len, queue, visited)
else
visited = MapSet.put(visited, pos)
new_states = next_states(chars, trie, pos, len)
queue =
Enum.reduce(new_states, queue, fn {next_pos, word}, acc_q ->
:queue.in({next_pos, words ++ [word]}, acc_q)
end)
bfs_loop(chars, trie, len, queue, visited)
end
end
end
end
Lastly we need to check the current set of letters of the passphrase and see if we can find a word within the trie:
# From position `pos`, find all valid words in trie
defp next_states(chars, trie, pos, len) do
do_next_states(Enum.drop(chars, pos), trie, pos, [], [], "")
end
defp do_next_states([], _trie, _pos, _acc, results, _current_word), do: results
defp do_next_states([h | t], trie, pos, acc, results, current_word) do
case Map.get(trie, h) do
nil ->
results
subtrie ->
new_word = current_word <> <<h>>
results =
if Map.has_key?(subtrie, :end) do
results ++ [{pos + length(acc) + 1, new_word}]
else
results
end
do_next_states(t, subtrie, pos, acc ++ [h], results, new_word)
end
end
We try to walk down the trie from the current phrase position. If the first letter matches a trie key, we add it to the current word and check if we've reached the end of a valid word. If so, we save this word and its end position. Then, we continue checking the next letters to find longer words. This way, we find all possible valid words starting from that position to expand our BFS search.