An infamous gang of cyber criminals named “The Gray Cyber Mob”, which is behind many hacking attacks and drug trafficking, has recently become a target for the FBI. After intercepting some of their messages, which looked like complete nonsense, the agency learned that they indeed encrypt their messages, and studied their method of encryption.
Their messages consist of lowercase latin letters only, and every word is encrypted separately as follows:
Convert every letter to its ASCII value. Add 1 to the first letter, and then for every letter from the second one to the last one, add the value of the previous letter. Subtract 26 from every letter until it is in the range of lowercase letters a-z in ASCII. Convert the values back to letters.
For instance, to encrypt the word “crime”
Decrypted message:crime
Step 1: | 99 | 114 | 105 | 109 | 101 |
Step 2: | 100 | 214 | 319 | 428 | 529 |
Step 3: | 100 | 110 | 111 | 116 | 113 |
Encrypted message: | d | n | o | t | q |
The FBI needs an efficient method to decrypt messages. Write a function named decrypt(word) that receives a string that consists of small latin letters only, and returns the decrypted word.
Explain your solution and analyze its time and space complexities.
Examples:
input: word = "dnotq" output: "crime" input: word = "flgxswdliefy" output: "encyclopedia"
Since the function should be used on messages with many words, make sure the function is as efficient as possible in both time and space. Explain the correctness of your function, and analyze its asymptotic runtime and space complexity.
Note: Most programing languages have built-in methods of converting letters to ASCII values and vica versa. You may search the internet for the appropriate method.
Constraints:
[time limit] 5000ms
[input] string word
[output] string
First of all, notice that the first letter is very easy to decrypt:
The decryption of the rest of the letters is done by almost the same algorithm - given the decrypted previous letter prev, and its value after the second step of encryption - denoted secondStepPrev:
Let’s examine the algorithm using the following notation:
The encryption algorithm gives the following relation for some integer m (which represents the number of times we need to add 26 to get to an ascii value):
enc[n] = dec[n] + secondStep[n-1] + 26m
By isolating dec[n], we get:
dec[n] = enc[n] - secondStep[n-1] - 26m
Though the value of m isn’t initially known, since the value of the decrypted letter must be in the ASCII range of a-z, the decrypted letter is easily found adding 26’s to enc[n] - secondStep[n] until it is in the right range.
Pseudocode:
function decrypt(word): secondStep = 1 decryption = "" for i from 0 to word.length - 1: newLetterAscii = asciiValue(word[i]) newLetterAscii = newLetterAscii - secondStep while (newLetterAscii < asciiValue('a')): newLetterAscii += 26 decryption = decryption + asciiToChar(newLetterAscii) secondStep += newLetterAscii return decryption
Note: The following functions were used but not defined, since the implementation is dependant of the programming language:
Time Complexity: the function’s asymptotic time complexity is O(N), where N is the length of the input string. the loop that iterates through the letters in the input is performed N times. In the loop, almost every step is done in O(1), except for the loop that is supposed to move the decrypted letter back to the range of a-z. Theoretically, the secondStep may grow linearly with the size of the input. There are two ways to deal with this:
Space Complexity: the space usage is also O(N) since the output is the same size of the input, and we only keep the output and the second step in storage.
import java.io.*;
import java.util.*;
class Solution {
static String decrypt(String word) {
int secondStep = 1;
String decryption = "";
for(int i = 0; i < word.length(); i++) {
int newLetterAscii = word.charAt(i);
newLetterAscii = newLetterAscii - secondStep;
while(newLetterAscii < 'a')
newLetterAscii += 26;
decryption += (char)newLetterAscii;
secondStep += newLetterAscii;
}
return decryption;
}
public static void main(String[] args) {
}
}