I wrote a function to solve a problem in Java, but it's still too brute force, and I'd like to optimize in terms of runtime.
Link to the description of the problem. The input consists of two lines: a fragment of plaintext, preceded by the message that is encrypted using some unknown character-to-character mapping. The challenge is to find out where the plaintext fragment could have come from.
What I have tried in the code below is to go over the encrypted string char by char (for the length of my key every time), and try to make a dictionary. If I could successfully assign every character from the key to a character from the encrypted text in a deterministic manner, then I note it down in a counter, and start over from the next character in the encrypted text.
So far this solution works on every test, until it reaches huge test case where my "brute force" solution is exceeding the time limit.
Any ideas on how could I improve performance or try a different approach?
package chasingsubs;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Scanner;
public class ChasingSubs {
private void decrypt(String line, String key) {
int counter = 0;
int startIndex = 0;
for (int i = 0; i < line.length() - key.length() + 1; i++) {
HashMap<Character, Character> dictionary = new HashMap<>();
HashSet<Character> used = new HashSet<>();
for (int j = 0; j < key.length(); j++) {
Character keyChar = key.charAt(j);
Character sourceChar = line.charAt(i+j);
if (dictionary.get(keyChar) == null) {
if (!used.contains(sourceChar)) {
dictionary.put(keyChar, sourceChar);
used.add(sourceChar);
}else{
break;
}
} else if (!dictionary.get(keyChar).equals(sourceChar)) {
break;
}
if (j == key.length() - 1) {
counter++;
if (counter == 1) {
startIndex = i;
}
}
}
}
if (counter == 0) {
System.out.println("0");
return;
}
if (counter == 1) {
System.out.println(line.substring(startIndex, startIndex + key.length()));
return;
}
System.out.println(counter);
}
public static void main(String[] args) {
ChasingSubs base = new ChasingSubs();
Scanner scanner = new Scanner(System.in);
base.decrypt(scanner.nextLine(), scanner.nextLine());
}
}