Last active
September 2, 2021 08:26
-
-
Save ashikuzzaman-ar/bea79663bb7a1eea47814a29b1a84241 to your computer and use it in GitHub Desktop.
Encrypt text in array diagonal and decrypt diagonally encrypted string to the original text.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.ArrayList; | |
import java.util.Collection; | |
import java.util.List; | |
import java.util.Scanner; | |
import java.util.stream.Collectors; | |
public class DiagonalEncoderDecoder { | |
/** | |
* String = "my name is" | |
* Word count = 3 | |
* Replace spaces by '_' = "my_name_is" | |
* Put that to a 2D array where row size is 3 (word count) | |
* ___________ | |
* |m|n|e|s| | | |
* ___________ | |
* | |y|a|_| | | |
* ___________ | |
* | | |_|m|i| | |
* ___________ | |
* <p> | |
* Now replace all empty spaces by '_' | |
* ___________ | |
* |m|n|e|s|_| | |
* ___________ | |
* |_|y|a|_|_| | |
* ___________ | |
* |_|_|_|m|i| | |
* ___________ | |
* <p> | |
* Now merge all rows in a single string | |
* <p> | |
* Encoded String = "mnes__ya_____mi" | |
* | |
* @param text String | |
* @return String | |
*/ | |
public static String encoder(String text) { | |
if (text == null) { | |
return null; | |
} | |
//Number of word(s) separated by space. | |
int wordCount = wordCount(text); | |
//List of lists for character matrix. | |
//Character matrix will dynamically grow that is why using list instead of array. | |
//In case of 2D array, array size will be (n x m) where n = wordCount and m = (text.length() / n + (n - 1)) | |
List<List<Character>> characters = new ArrayList<>(wordCount); | |
//Initializing lists and inserting incremental '_' for each row so that next insertion occurs diagonally | |
for (int i = 0; i < wordCount; i++) { | |
List<Character> list = new ArrayList<>(); | |
for (int j = 0; j < i; j++) { | |
list.add('_'); | |
} | |
characters.add(list); | |
} | |
int counter = 0; | |
int textLength = text.length(); | |
//Inserting each character of the source diagonally in matrix | |
while (counter < textLength) { | |
for (int i = 0; i < wordCount; i++) { | |
if (counter < textLength) { | |
char c = text.charAt(counter++); | |
//Inserting character and replacing space by '_' | |
characters.get(i).add(c == ' ' ? '_' : c); | |
} | |
} | |
} | |
//Eventually the last row will be the longest | |
int maxSize = characters.get(wordCount - 1).size(); | |
//Filling top rows by '_' up to the size of maxSize | |
for (List<Character> character : characters) { | |
while (character.size() < maxSize) { | |
character.add('_'); | |
} | |
} | |
//Merging all characters to a single line string and returning the result | |
return characters.stream().parallel().flatMap(Collection::stream).map(String::valueOf).collect(Collectors.joining("")); | |
} | |
/** | |
* Count number of words in a string separated by space and returning the number | |
* | |
* @param text String | |
* @return int | |
*/ | |
public static int wordCount(String text) { | |
return text == null ? 0 : text.split("\\s").length; | |
} | |
/** | |
* Given an encoded string and number of encoded worlds in the string. | |
* The string is encoded diagonally such that, | |
* encodedString = "mnes__ya_____mi" | |
* wordCount = 3 | |
* ___________ | |
* |m|n|e|s|_| | |
* ___________ | |
* |_|y|a|_|_| | |
* ___________ | |
* |_|_|_|m|i| | |
* ___________ | |
* <p> | |
* The following 2D array with row number equals to word count has indexed (0, 0) = 'm', (1, 1) = 'y', | |
* (2, 2) = '_'. You have to return to the top again from (0, 1) = 'n', (1, 2) = 'a' and so on. You will | |
* find a string of three words which is "my_name_is", separated by '_'. Now replace '_' by space, and | |
* you will find decoded string which is "my name is". Empty spaces from both side will be trimmed. | |
* | |
* @param wordCount int | |
* @param encodedString String | |
* @return String | |
*/ | |
public static String decoder(int wordCount, String encodedString) { | |
if (encodedString == null || wordCount == 0) { | |
return null; | |
} | |
int length = encodedString.length(); | |
int rowLength = length / wordCount; | |
//Row length cannot be less than word count | |
if (rowLength < wordCount) { | |
throw new RuntimeException("Invalid world count " + wordCount); | |
} | |
//part list is the [wordCount] rows of the matrix | |
List<String> part = new ArrayList<>(wordCount); | |
for (int i = 0; i < wordCount; i++) { | |
int beginIndex = i * rowLength; | |
int endIndex = beginIndex + rowLength; | |
/* | |
* ___________ | |
* |m|n|e|s|_| | |
* ___________ | |
* |_|y|a|_|_| | |
* ___________ | |
* |_|_|_|m|i| | |
* ___________ | |
* Here we are ignoring all unnecessary '_' from the rows so that we can travers horizontally later. | |
* Final list looks like, | |
* ___________ | |
* |m|n|e|s|_| | |
* ___________ | |
* |y|a|_|_| | |
* _________ | |
* |_|m|i| | |
* _______ | |
*/ | |
part.add(encodedString.substring(beginIndex + i, endIndex)); | |
} | |
StringBuilder builder = new StringBuilder(); | |
//We are traversing from beginning to the length of row length (length of initial row) for each row. | |
for (int i = 0; i < rowLength; i++) { | |
for (int j = 0; j < wordCount; j++) { | |
//Each row length is not same as first row, we are checking whether row length is accessible or not. | |
if (part.get(j).length() > i) { | |
builder.append(part.get(j).charAt(i)); | |
} | |
} | |
} | |
//Finally, replacing '_' by space and returning after trimming. | |
return builder.toString().replace("_", " ").trim(); | |
} | |
public static void main(String[] args) { | |
try (Scanner scanner = new Scanner(System.in)) { | |
String text = scanner.nextLine().trim(); | |
System.out.println("Original => " + text); | |
String encodedString = encoder(text); | |
System.out.println("Encoded => " + encodedString); | |
String decodedString = decoder(wordCount(text), encodedString); | |
System.out.println("Decoded => " + decodedString); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment