java.lang.ThreadDeath error message when running code - java

So I have written a Java Program (Which I have attached the code for below) for a cryptographic cipher I designed (based on the SPN cipher but with a few modifications). Anyways, when I run my program, the code instantly stops and I receive a java.lang.ThreadDeath error. I have tried even adding a print statement to the very beginning (as in first line) of my main method (so it was the first thing processed by my program), but I had no luck, Java stopped before my print statement could even run.
Here is my code:
package SSPN;
import java.io.*;
import java.util.*;
public class Main throws IOException{
public static final int NUM_ROUNDS = 1;
public static final File f = new File("sBoxes.txt");
//Need better comments!!
//For each character, prints out a binary string of length 7. Does zero - padding!
public static String[] plaintextToCharacterBinarySequence(String plaintext)
{
//Getting int values
int[] charRepresentations = new int[plaintext.length()];
for (int i = 0; i < charRepresentations.length; i++)
{
char ch = plaintext.charAt(i);
int asciiValue = (int)ch;
charRepresentations[i] = asciiValue;
}
String[] binValues = new String[charRepresentations.length];
System.out.print("Binary values are: ");
for (int i = 0; i < binValues.length; i++)
{
String str = Integer.toBinaryString(charRepresentations[i]);
StringBuilder sb = new StringBuilder(str);
if (str.length() !=7)
{
int DIFF = 7 - str.length(); //As it is an Ascii Value, must be less than length 7
for (int j = 7; j > (7 - DIFF); j--)
{
sb.insert(0,"0");
}
}
str = sb.toString();
binValues[i] = str;
System.out.print(binValues[i] + " ");
}
System.out.println();
return binValues;
}
public static String binarySequenceToString(String[] sequence)
{
StringBuilder sb = new StringBuilder();
for (int i =0; i < sequence.length; i++)
{
int val = Integer.parseInt(sequence[i], 2);
char ch = (char) val;
sb.append(ch);
}
return sb.toString();
}
/*We define an instance of the affine cipher (for extra security), with a = length of message,b = ascii value of 1st character.
m = 128. Then, we convert the output to (zero-padded) 7-bit binary number, and store the result as the output of a hash
table (where the input binary number is the key)*/
public static HashMap<String, String> defineandStoreSBoxes(File f, int lengthOfMessage, int firstAsciiValue) throws FileNotFoundException, IOException
{
BufferedReader br = new BufferedReader(new FileReader(f));
HashMap<String, String> hm = new HashMap <String, String>();
String currentSBox;
while ((currentSBox = br.readLine()) != null)
{
int base10Val = Integer.parseInt(currentSBox, 2);
int encryptedOutput = lengthOfMessage * base10Val + firstAsciiValue; //(LIMITATION: Without modding by 128, encryptedOutput Cannot exceed Integer.MAX_VALUE)
String binOutput = Integer.toBinaryString(encryptedOutput);
StringBuilder sb = new StringBuilder(binOutput);
if (binOutput.length() !=7)
{
int DIFF = 7 - binOutput.length(); //As it is an Ascii Value, must be less than length 7
for (int j = 7; j > (7 - DIFF); j--)
{
sb.insert(0,"0");
}
}
binOutput = sb.toString();
hm.put(currentSBox, binOutput);
}
br.close();
return hm;
}
//This method performs bitwise XOR on each block of the plaintext and the bits of the round key (which are the same size)
public static String[] xorSubkey(String[] currentText, String roundKey )
{
for (int i =0; i < roundKey.length(); i++)
{
StringBuilder sb = new StringBuilder();
String binStr = currentText[i];
for (int j =0; j < 7; j++)
{
int chCurrent = Character.getNumericValue(binStr.charAt(j)); //Either 0 or 1
int chKey = Character.getNumericValue(roundKey.charAt((1 * 7)+ j));
if (chCurrent == chKey)
{
sb.append("0");
}
else
{
sb.append("1");
}
}
currentText[i] = sb.toString();
}
return currentText;
}
public static String[] sBoxSubstitution(String[] currentText, HashMap <String,String> hm)
{
for (int i =0; i < currentText.length; i++)
{
String val = hm.get(currentText[i]);
currentText[i] = val;
}
return currentText;
}
public static String[] linTransform(String[] currentText)
{
int shift = currentText.length % 7;
for (int i =0; i < currentText.length; i++)
{
StringBuilder sb = new StringBuilder(currentText[i]);
String sub = currentText[i].substring(shift, 7);
sb.insert(0, sub);
sb.delete(currentText[i].length(), currentText[i].length() + (7 - shift));
currentText[i] = sb.toString();
}
return currentText;
}
public static String[] encrypt(String plaintext, String[] roundKeys) throws IOException
{
String[] binaryText = plaintextToCharacterBinarySequence(plaintext);
HashMap<String, String> hm = defineandStoreSBoxes(f, plaintext.length(), (int) plaintext.charAt(0));
String[] xoredSequence, substitutedSequence,transformedSequence = null;
//The first Num_Rounds -1 Rounds
for (int i =0; i < NUM_ROUNDS -1; i++)
{
xoredSequence = xorSubkey(binaryText, roundKeys[i]);
substitutedSequence = sBoxSubstitution(xoredSequence, hm);
transformedSequence = linTransform(substitutedSequence);
}
// the final round
xoredSequence = xorSubkey(transformedSequence, roundKeys[roundKeys.length - 2]); //Make sure this isnt null
substitutedSequence = sBoxSubstitution(xoredSequence, hm);
//Final xor Subkeying
String[] ciphertext = xorSubkey(substitutedSequence, roundKeys[roundKeys.length - 1]); //Make sure this isnt null
return ciphertext;
}
//DECRYPTING
public static String[] decrypt(String textToDecrypt, String[] roundKeys) throws IOException
{
String[] bitCiphertext = plaintextToCharacterBinarySequence(textToDecrypt);
HashMap<String, String> hm= defineandStoreSBoxes(f,textToDecrypt.length(), (int)textToDecrypt.charAt(0) ); //Make sure this is reversed
String[] xoredSequence, substitutedSequence,transformedSequence = null;
//Decrypting final ciphertext
String[] finalXOR = xorSubkey(bitCiphertext, roundKeys[roundKeys.length - 1]);
// Final round
substitutedSequence = reverseSBox(finalXOR, hm);
xoredSequence = xorSubkey(substitutedSequence, roundKeys[roundKeys.length - 2]);
//Reversing the loop order
for (int i = NUM_ROUNDS -1; i >= 0; i--)
{
transformedSequence = reverseLinTransform(substitutedSequence);
substitutedSequence = reverseSBox(transformedSequence, hm);
xoredSequence = xorSubkey(substitutedSequence, roundKeys[i]);
}
String[] plaintext = xoredSequence;
return plaintext;
}
public static String[] reverseSBox(String[] value, HashMap <String, String> hm)
{
for (int i =0; i < value.length; i++)
{
for (Map.Entry<String, String> entry : hm.entrySet())
{
if (value[i].equals(entry.getValue())) //Because s-boxes are bijective
{
value[i] = entry.getKey();
}
}
}
return value;
}
public static String[] reverseLinTransform(String[] value)
{
int shift = 7 - (value.length %7);
for (int i =0; i < value.length; i++)
{
StringBuilder sb = new StringBuilder(value[i]);
String sub = value[i].substring(shift, 7);
sb.insert(0, sub);
sb.delete(value[i].length(), value[i].length() + (7 - shift));
value[i] = sb.toString();
}
return value;
}
public static boolean isGoodRoundKey(String key, int plainTextLength)
{
if (plainTextLength == key.length() && key.length() % 7 ==0 && isBinary(key) ==true)
{
return true;
}
else
{
return false;
}
}
public static boolean isBinary(String number)
{
for (int i =0; i < number.length(); i++)
{
char c = number.charAt(i);
if (c != '0' && c != '1')
{
return false;
}
}
return true;
}
public static void main(String[] args) throws IOException
{
System.out.println("Inside main");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); //Buffered reader will read in plaintext, and round keys
System.out.print("Enter the text that you would like to encrypt: ");
String plaintext = br.readLine();
int numChars = plaintext.length();//The total number of characters that make up this string
String[] roundKeys = new String[NUM_ROUNDS + 1];//Each box will have 7 bits
System.out.println("The cipher will encrypt for "+ NUM_ROUNDS + "rounds, so you will need to enter some round keys. ");
System.out.println("Each round key must be a sequence of zeroes and ones, and must be exactly seven times the length of the plaintext string");
//Storing all the round keys in the array!
for (int i =0; i <= NUM_ROUNDS; i++)
{
if (i ==0)
{
System.out.print("Enter the round key for the 1st round: ");
}
else if (i ==1)
{
System.out.print("Enter the round key for the 2nd round: ");
}
else if (i ==2)
{
System.out.print("Enter the round key for the 3rd round: ");
}
else if (i == NUM_ROUNDS)
{
System.out.print("Enter the round key that will be XORed at the very end of all the rounds ");
}
else
{
System.out.print("Enter the round key for the " + i+1 + "th round: ");
}
roundKeys[i] = br.readLine();
System.out.println();
/*Check to make sure the round key that is passed in is valid. If it is not, an error message will be printed to the user,
prompting them to enter a valid round key. This will loop indefinitely until a valid round key is entered.
*/
if (isGoodRoundKey(roundKeys[i],plaintext.length() ) !=true)
{
boolean isValid = false;
while(isValid == false)
{
System.out.println("ERROR: the key you entered is not a valid key for this cipher.");
System.out.println("Please enter another key: ");
String new_key = br.readLine();
if (isGoodRoundKey(new_key, plaintext.length()) ==true)
{
roundKeys[i] = new_key;
isValid = true;
}
}
}
}
br.close();
String[] bitCiphertext = encrypt(plaintext, roundKeys);
String ciphertext = binarySequenceToString(bitCiphertext);
System.out.println("The encryption of " + plaintext + " is: "+ ciphertext);
String[] discoveredBitPlaintext = decrypt(ciphertext, roundKeys);
String discoveredPlaintext = binarySequenceToString(bitCiphertext);
System.out.println("The encryption of " + ciphertext + " is: " + discoveredPlaintext);//Reverse order of round Keys
}
}

Related

Write a BreakCaesarCipher program

so I have a programming question. I want to be able to create a breakCaesarCipher class that does the following:
1) splitting the encrypted message
2) determining the two decryption keys
3) creating an instance of CaesarCipherTwo with those keys.
4) calling the decrypt method.
I don't know where to begin. I'm confused as to how one might split the encrypted message. In a previous lesson we did it like so:
import edu.duke.*;
public class CaesarBreaker2 {
public int[] countOccurrencesOfLetters(String message) {
//snippet from lecture
String alph = "abcdefghijklmnopqrstuvwxyz";
int[] counts = new int[26];
for (int k=0; k < message.length(); k++) {
char ch = Character.toLowerCase(message.charAt(k));
int dex = alph.indexOf(ch);
if (dex != -1) {
counts[dex] += 1;
}
}
return counts;
}
public int maxIndex(int[] values) {
int maxDex = 0;
for (int k=0; k < values.length; k++) {
if (values[k] > values[maxDex]) {
maxDex = k;
}
}
return maxDex;
}
public String decrypt(String encrypted) {
CaesarCipher cc = new CaesarCipher();
int[] freqs = countOccurrencesOfLetters(encrypted);
int maxDex = maxIndex(freqs);
int dkey = maxDex - 4;
if (maxDex < 4) {
dkey = 26 - (4-maxDex);
}
return cc.encrypt(encrypted,26-dkey);
}
public String halfOfString(String message, int start) {
StringBuilder halfString = new StringBuilder();
for (int index=start;index < message.length();index += 2) {
halfString.append(message.charAt(index));
}
return halfString.toString();
}
public int getKey(String s) {
int[] letterFreqs = countOccurrencesOfLetters(s);
int maxDex = maxIndex(letterFreqs);
int dkey = maxDex - 4;
if (maxDex < 4) {
dkey = 26 - (4-maxDex);
}
return 26-dkey;
}
public String decryptTwoKeys(String encrypted) {
String firstHalfEncrypted = halfOfString(encrypted,0);
String secondHalfEncrypted = halfOfString(encrypted,1);
int firstHalfKey = getKey(firstHalfEncrypted);
int secondHalfKey = getKey(secondHalfEncrypted);
CaesarCipherTwo ccT = new CaesarCipherTwo();
System.out.println("First key:\t" + firstHalfKey + "\nSecond key:\t"
+ secondHalfKey);
return ccT.encryptTwoKeys(encrypted,firstHalfKey,secondHalfKey);
}
public void testDecrypt() {
FileResource fileResource = new FileResource();
String encrypted = fileResource.asString();
System.out.println("Encrypted message:\n" + encrypted);
System.out.println("\nDecrypted message:\n" + decryptTwoKeys(encrypted));
String encrypted2 = "Aal uttx hm aal Qtct Fhljha pl Wbdl. Pvxvxlx!";
System.out.println("Encrypted message:\n" + encrypted2);
System.out.println("\nDecrypted message:\n" + decryptTwoKeys(encrypted2));
}
}
but I don't understand how to convert this code so it will work in this new class called TestCaesarCipherTwo. Here is the code for TestCaesarCipherTwo:
import edu.duke.*;
public class TestCaesarCipherTwo {
public int[] countOccurrencesOfLetters(String message) {
//snippet from lecture
String alph = "abcdefghijklmnopqrstuvwxyz";
int[] counts = new int[26];
for (int k=0; k < message.length(); k++) {
char ch = Character.toLowerCase(message.charAt(k));
int dex = alph.indexOf(ch);
if (dex != -1) {
counts[dex] += 1;
}
}
return counts;
}
public int maxIndex(int[] values) {
int maxDex = 0;
for (int k=0; k < values.length; k++) {
if (values[k] > values[maxDex]) {
maxDex = k;
}
}
return maxDex;
}
public String halfOfString(String message, int start) {
StringBuilder halfString = new StringBuilder();
for (int index=start;index < message.length();index += 2) {
halfString.append(message.charAt(index));
}
return halfString.toString();
}
public void simpleTests() {
FileResource fileResource = new FileResource();
String fileAsString = fileResource.asString();
CaesarCipherTwoKeys cctk = new CaesarCipherTwoKeys(17, 3);
String encrypted = cctk.encrypt(fileAsString);
System.out.println("Encrypted string:\n"+encrypted);
String decrypted = cctk.decrypt(encrypted);
System.out.println("Decrypted string:\n"+decrypted);
String blindDecrypted = breakCaesarCipher(encrypted);
System.out.println("Decrypted string using breakCaesarCipher():\n"+blindDecrypted);
}
public String breakCaesarCipher(String input) {
int[] freqs = countOccurrencesOfLetters(input);
int freqDex = maxIndex(freqs);
int dkey = freqDex - 4;
if (freqDex < 4) {
dkey = 26 - (4-freqDex);
}
CaesarCipherTwoKeys cctk = new CaesarCipherTwoKeys(dkey);
return cctk.decrypt(input);
}
}
WARNING: I also have a constructor error on this line CaesarCipherTwoKeys cctk = new CaesarCipherTwoKeys(dkey); stating CaesarCipherTwoKeys in class CaesarCipherTwoKeys cannot be applied to given types; required int,int; found int....
Can anyone show me how to change my code so that my breakCaesarCipher method splits the encrypted message, determines the two decryption keys used to encrypt the message, create an instance of CaesarCipherTwo with those two keys, and call the decrypt method? Any suggestions are welcome. Please let me know if you want more details into the nature of this problem.

To split a string and to check if they are anagram to each other

I am trying to solve this question: https://www.hackerrank.com/challenges/anagram
Here's my code:
import java.util.*;
public class Anagram {
public static void main(String[] args)
{
Scanner reader = new Scanner(System.in);
int t = reader.nextInt();
while((t--) > 0)
{
String input = reader.nextLine();
if((input.length()) % 2 == 1)
System.out.println(-1);
else
{
int x = input.length();
int q = (int)(Math.floor((x / 2)));
String input1 = input.substring(0, q);
String input2 = input.substring(q, x);
int [] count2 = new int[26];
for(int i = 0; i < input2.length(); i++)
{
char ch2 = input2.charAt(i);
count2[ch2 - 'a']++;
}
// int [] count1 = new int[26];
for(int i = 0; i < input1.length(); i++)
{
char ch1 = input1.charAt(i);
if(count2[i] > 0)
count2[ch1 - 'a']--;
}
int count = 0;
for(int j = 0; j < 26; j++)
{
count = count + Math.abs(count2[j]);
}
System.out.println(count);
}
}
}
}
Sample Input
6
aaabbb
ab
abc
mnop
xyyx
xaxbbbxx
Expected Output
3
1
-1
2
0
1
My output
0
4
1
-1
2
2
Can anyone please tell me where it went wrong? I couldn't find the error...
Your first output always comes 0, because of this line:
int t = reader.nextInt();
followed by reader.nextLine();. Check this post for more details on that. For quick fix, change that line to:
int t = Integer.parseInt(reader.nextLine());
Now, let's start with the below two statements:
int x = input.length();
int q = (int)(Math.floor((x/2)));
No need to do a Math.floor there. x/2 is an integer division, and will give you integer result only.
Moving to the 2nd for loop. You used the following condition:
if(count2[i]>0)
count2[ch1-'a']--;
Notice the mistake there in condition? It should be count2[ch1 - 'a'] > 0. And also, you will miss the case where that count is not greater than 0, in which case you would have to do a ++. BTW, since you're anyways doing a Math.abs(), you don't need the condition. Just do a --:
for( int i = 0; i < input1.length(); i++ ) {
char ch1 = input1.charAt(i);
count2[ch1-'a']--;
}
BTW, the final result would be count / 2, and not count, because count contains the total mismatch from input1 to input2 and vice-versa. But we just have to fix one of them to match the other. So, just consider half the total mismatch.
You can use this to check if two strings are palindromes:
String original = "something";
String reverse = new StringBuilder(original).reverse().toString();
boolean anagram = original.equals(reverse);
As per your question, main logic could be changed to something like below.
Note - I have added only the main logic and excluded the user inputs here.
public static void main(String[] args) {
String str = "acbacccbaac";
int len = str.length();
String str1 = null, str2 = null;
if(len %2 != 0) {//check for odd length
str1 = str.substring(0, len/2);
str2 = str.substring(len/2+1, len);
}else {//check for even length
str1 = str.substring(0, len/2);
str2 = str.substring(len/2, len);
}
char[] arr1 = str1.toLowerCase().toCharArray();
Arrays.sort(arr1);
char[] arr2 = str2.toLowerCase().toCharArray();
Arrays.sort(arr2);
if(Arrays.equals(arr1, arr2))
System.out.println("Yes");
else
System.out.println("No");
}
I implemented this way for the same problem in my HackerRank profile, and works great.
This is my solution to the prob and it works!
static int anagram(String s) {
String a = "";
String b = "";
if (s.length() % 2 == 0) {
a = s.substring(0, s.length() / 2);
b = s.substring((s.length() / 2), s.length());
}
if (s.length() % 2 != 0) {
a = s.substring(0, s.length() / 2);
b = s.substring((s.length() / 2), s.length());
}
if (a.length() == b.length()) {
char[] aArray = a.toCharArray();
char[] bArray = b.toCharArray();
HashMap<Character, Integer> aMap = new HashMap<Character, Integer>();
HashMap<Character, Integer> bMap = new HashMap<Character, Integer>();
for (char c : aArray) { // prepare a Hashmap of <char>,<count> for first string
if (aMap.containsKey(c)) {
aMap.put(c, aMap.get(c) + 1);
} else {
aMap.put(c, 1);
}
}
for (char c : bArray) {// prepare a Hashmap of <char>,<count> for second string
if (bMap.containsKey(c)) {
bMap.put(c, bMap.get(c) + 1);
} else {
bMap.put(c, 1);
}
}
int change = 0;
for (Map.Entry<Character, Integer> entry : bMap.entrySet()) {
System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
if (!aMap.containsKey(entry.getKey())) {
change += entry.getValue();
} else {
if (entry.getValue() > aMap.get(entry.getKey())) {
change += entry.getValue() - aMap.get(entry.getKey());
} else {
//change += entry.getValue();
}
}
}
return change;
} else {
return -1;
}
}

For loop that counts how many characters repeat in a string, then removes the repeated characters

Example: attack at noon = a3t3c1k1 2n2o2
It also counts spaces.
Here is what I have, but it doesn't seem to be returning correctly:
String getCount(String str) {
String R = "";
int l = S.length();
int cnt = 1;
for (int i = 0; i < l; i++)
for (int j = i + 1; j < l; j++)
if (S.charAt(j) == S.charAt(i)) {
cnt++;
R = R + S.charAt(i)+""+cnt;
System.out.print(S.charAt(i) + cnt);
}
return R;
}
If the strings are small enough you don't need anything fancy, just brute force it (for attack at noon this runs in 3ms).
This code will iterate over all characters, if not found before it will append the character and its count to a StringBuilder which is then printed before terminating.
import java.util.HashMap;
public class Counter {
HashMap<String, Integer> counts;
StringBuilder result;
public static void main(String[] args) {
Counter counter = new Counter();
counter.countString("attack at noon");
}
void countString(String S) {
counts = new HashMap<String, Integer>();
result = new StringBuilder();
String[] split = S.split("");
for (int i = 1; i < split.length; i++) {
String c = split[i];
countChar(c, S);
}
System.out.println(result);
}
void countChar(String c, String s) {
Integer integer = counts.get(c);
if (integer == null) {
int i = s.length() - s.replace(c, "").length();
counts.put(c, i);
result.append(c).append(i);
}
}
}
public static void main(String[] args) {
System.out.println(getCount("attack at noon"));
}
String getCount(String str) {
String R = "";
String S = str;
int l = S.length();
int cnt;
first:for (int i = 0; i < l; i++) { //Foreach letter
cnt = 0;
for (int j = i; j < l; j++) {
if (S.charAt(j) == S.charAt(i)) {
if ( R.indexOf(S.charAt(j)) != -1 ) {
continue first;
}
cnt++;
}
}
R = R + S.charAt(i) + cnt;
}
return R;
}
Output: a3t3c1k1 2n2o2
You should maintain a int[] that stores the counts of each letter in the alphabet.
private int[] getDuplicates(String string) {
String str = string.toLowerCase();
int[] charCounts = new int[27];
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (c == ' ') {
charCounts[26]++;
}
else {
charCounts[c - 'a']++;
}
}
return charCounts;
}
This method will return an array where the 0th index corresponds to the number of times 'a' shows up in your string
public String getCharCounts(String string) {
int[] charCounts = getDuplicates(string);
StringBuffer strBuff = new StringBuffer();
for (int i = 0; i < charCounts.length; i++) {
if (charCounts[i] > 0) {
char c;
if (i < 26) {
c = (char)(i + (int)'a');
}
else {
c = ' ';
}
strBuff.append(c);
strBuff.append(charCounts[i]);
}
}
return strBuff.toString();
}
This method uses the array you get from the first method and appends the character followed by its count. This is more efficient because you only need to pass through the String one time to get the counts and then pass one time through the array to formulate your deduped String. The run-time is O(n)
Here's my enterprise level solution
attack at noon = a3t3c1k1 2n2o2
Here's another test of the code:
For loop that counts how many characters repeat in a string,
then removes the repeated characters =
f1o6r9 15l1p3t10h6a9c5u1n5s5w1m2y1e11i2g1,1v1d1
And here's the code:
package com.ggl.testing;
import java.util.ArrayList;
import java.util.List;
public class Counter {
private List<CharacterCount> characterCounts;
public Counter() {
this.characterCounts = new ArrayList<CharacterCount>();
}
public void countString(String s) {
s = s.toLowerCase();
for (int i = 0; i < s.length(); i++) {
CharacterCount cc = new CharacterCount(s.charAt(i));
addCharacterCount(cc);
}
}
private void addCharacterCount(CharacterCount cc) {
for (CharacterCount count : characterCounts) {
if (count.getCharacter() == cc.getCharacter()) {
count.setCount(count.getCount() + 1);
return;
}
}
cc.setCount(1);
characterCounts.add(cc);
}
public String returnString() {
StringBuilder builder = new StringBuilder();
for (CharacterCount count : characterCounts) {
builder.append(count.getCharacter());
builder.append(count.getCount());
}
return builder.toString();
}
public static void main(String[] args) {
String s = "For loop that counts how many characters " +
"repeat in a string, then removes the repeated " +
"characters";
Counter counter = new Counter();
counter.countString(s);
System.out.println(s + " = " + counter.returnString());
}
public class CharacterCount {
private char character;
private int count;
public CharacterCount(char character) {
this.character = character;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public char getCharacter() {
return character;
}
}
}
Use a LinkedHashMap to store the counts for each character because it maintains insert order.
public static String countChars(String str) {
Map<Character, Integer> map = new LinkedHashMap<Character, Integer>();
for( char c : str.toCharArray() ) {
if( map.containsKey( c ) ) {
map.put( c, map.get( c ) + 1 );
} else {
map.put( c, 1 );
}
}
StringBuilder sb = new StringBuilder();
for( Character key : map.keySet() ) {
sb.append(key.toString() + map.get( key ) );
}
return sb.toString();
}
Using Guava.
String getGroup(final String string) {
StringBuffer stringBuffer = new StringBuffer();
for(char c : string.toCharArray()) {
int occurances = CharMatcher.is(c).countIn(string);
if (stringBuffer.indexOf(String.valueOf(c)) == -1) {
stringBuffer.append(String.valueOf(c) + occurances);
}
}
return stringBuffer.toString();
}

How to Find the Longest Palindrome (java)

Hi I've been doing this java program, i should input a string and output the longest palindrome that can be found ..
but my program only output the first letter of the longest palindrome .. i badly need your help .. thanks!
SHOULD BE:
INPUT : abcdcbbcdeedcba
OUTPUT : bcdeedcb
There are two palindrome strings : bcdcb and bcdeedcb
BUT WHEN I INPUT : abcdcbbcdeedcba
output : b
import javax.swing.JOptionPane;
public class Palindrome5
{ public static void main(String args[])
{ String word = JOptionPane.showInputDialog(null, "Input String : ", "INPUT", JOptionPane.QUESTION_MESSAGE);
String subword = "";
String revword = "";
String Out = "";
int size = word.length();
boolean c;
for(int x=0; x<size; x++)
{ for(int y=x+1; y<size-x; y++)
{ subword = word.substring(x,y);
c = comparisonOfreverseword(subword);
if(c==true)
{
Out = GetLongest(subword);
}
}
}
JOptionPane.showMessageDialog(null, "Longest Palindrome : " + Out, "OUTPUT", JOptionPane.PLAIN_MESSAGE);
}
public static boolean comparisonOfreverseword(String a)
{ String rev = "";
int tempo = a.length();
boolean z=false;
for(int i = tempo-1; i>=0; i--)
{
char let = a.charAt(i);
rev = rev + let;
}
if(a.equalsIgnoreCase(rev))
{
z=true;
}
return(z);
}
public static String GetLongest(String sWord)
{
int sLength = sWord.length();
String Lpalindrome = "";
int storage = 0;
if(storage<sLength)
{
storage = sLength;
Lpalindrome = sWord;
}
return(Lpalindrome);
}
}
modified program..this program will give the correct output
package pract1;
import javax.swing.JOptionPane;
public class Palindrome5
{
public static void main(String args[])
{
String word = JOptionPane.showInputDialog(null, "Input String : ", "INPUT", JOptionPane.QUESTION_MESSAGE);
String subword = "";
String revword = "";
String Out = "";
int size = word.length();
boolean c;
String Lpalindrome = "";
int storage=0;
String out="";
for(int x=0; x<size; x++)
{ for(int y=x+1; y<=size; y++)
{ subword = word.substring(x,y);
c = comparisonOfreverseword(subword);
if(c==true)
{
int sLength = subword.length();
if(storage<sLength)
{
storage = sLength;
Lpalindrome = subword;
out=Lpalindrome;
}
}
}
}
JOptionPane.showMessageDialog(null, "Longest Palindrome : " + out, "OUTPUT", JOptionPane.PLAIN_MESSAGE);
}
public static boolean comparisonOfreverseword(String a)
{ String rev = "";
int tempo = a.length();
boolean z=false;
for(int i = tempo-1; i>=0; i--)
{
char let = a.charAt(i);
rev = rev + let;
}
if(a.equalsIgnoreCase(rev))
{
z=true;
}
return(z);
}
}
You have two bugs:
1.
for(int y=x+1; y<size-x; y++)
should be
for(int y=x+1; y<size; y++)
since you still want to go all the way to the end of the string. With the previous loop, since x increases throughout the loop, your substring sizes decrease throughout the loop (by removing x characters from their end).
2.
You aren't storing the longest string you've found so far or its length. The code
int storage = 0;
if(storage<sLength) {
storage = sLength;
...
is saying 'if the new string is longer than zero characters, then I will assume it is the longest string found so far and return it as LPalindrome'. That's no help, since we may have previously found a longer palindrome.
If it were me, I would make a static variable (e.g. longestSoFar) to hold the longest palindrome found so far (initially empty). With each new palindrome, check if the new one is longer than longestSoFar. If it is longer, assign it to longestSoFar. Then at the end, display longestSoFar.
In general, if you're having trouble 'remembering' something in the program (e.g. previously seen values) you have to consider storing something statically, since local variables are forgotten once their methods finish.
public class LongestPalindrome {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String S= "abcdcba";
printLongestPalindrome(S);
}
public static void printLongestPalindrome(String S)
{
int maxBack=-1;
int maxFront = -1;
int maxLength=0;
for (int potentialCenter = 0 ; potentialCenter < S.length();potentialCenter ++ )
{
int back = potentialCenter-1;
int front = potentialCenter + 1;
int longestPalindrome = 0;
while(back >=0 && front<S.length() && S.charAt(back)==S.charAt(front))
{
back--;
front++;
longestPalindrome++;
}
if (longestPalindrome > maxLength)
{
maxLength = longestPalindrome+1;
maxBack = back + 1;
maxFront = front;
}
back = potentialCenter;
front = potentialCenter + 1;
longestPalindrome=0;
while(back >=0 && front<S.length() && S.charAt(back)==S.charAt(front))
{
back--;
front++;
longestPalindrome++;
}
if (longestPalindrome > maxLength)
{
maxLength = longestPalindrome;
maxBack = back + 1;
maxFront = front;
}
}
if (maxLength == 0) System.out.println("There is no Palindrome in the given String");
else{
System.out.println("The Longest Palindrome is " + S.substring(maxBack,maxFront) + "of " + maxLength);
}
}
}
I have my own way to get longest palindrome in a random word. check this out
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println(longestPalSubstr(in.nextLine().toLowerCase()));
}
static String longestPalSubstr(String str) {
char [] input = str.toCharArray();
Set<CharSequence> out = new HashSet<CharSequence>();
int n1 = str.length()-1;
for(int a=0;a<=n1;a++)
{
for(int m=n1;m>a;m--)
{
if(input[a]==input[m])
{
String nw = "",nw2="";
for (int y=a;y<=m;y++)
{
nw=nw+input[y];
}
for (int t=m;t>=a;t--)
{
nw2=nw2+input[t];
}
if(nw2.equals(nw))
{
out.add(nw);
break;
}
}
}
}
int a = out.size();
int maxpos=0;
int max=0;
Object [] s = out.toArray();
for(int q=0;q<a;q++)
{
if(max<s[q].toString().length())
{
max=s[q].toString().length();
maxpos=q;
}
}
String output = "longest palindrome is : "+s[maxpos].toString()+" and the lengths is : "+ max;
return output;
}
this method will return the max length palindrome and the length of it. its a way that i tried and got the answer. and this method will run whether its a odd length or even length.
public class LongestPalindrome {
public static void main(String[] args) {
HashMap<String, Integer> result = findLongestPalindrome("ayrgabcdeedcbaghihg123444456776");
result.forEach((k, v) -> System.out.println("String:" + k + " Value:" + v));
}
private static HashMap<String, Integer> findLongestPalindrome(String str) {
int i = 0;
HashMap<String, Integer> map = new HashMap<String, Integer>();
while (i < str.length()) {
String alpha = String.valueOf(str.charAt(i));
if (str.indexOf(str.charAt(i)) != str.lastIndexOf(str.charAt(i))) {
String pali = str.substring(i, str.lastIndexOf(str.charAt(i)) + 1);
if (isPalindrome(pali)) {
map.put(pali, pali.length());
i = str.lastIndexOf(str.charAt(i));
}
}
i++;
}
return map;
}
public static boolean isPalindrome(String input) {
for (int i = 0; i <= input.length() / 2; i++) {
if (input.charAt(i) != input.charAt(input.length() - 1 - i)) {
return false;
}
}
return true;
}
}
This approach is simple.
Output:
String:abcdeedcba Value:10
String:4444 Value:4
String:6776 Value:4
String:ghihg Value:5
This is my own way to get longest palindrome. this will return the length and the palindrome word
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println(longestPalSubstr(in.nextLine().toLowerCase()));
}
static String longestPalSubstr(String str) {
char [] input = str.toCharArray();
Set<CharSequence> out = new HashSet<CharSequence>();
int n1 = str.length()-1;
for(int a=0;a<=n1;a++)
{
for(int m=n1;m>a;m--)
{
if(input[a]==input[m])
{
String nw = "",nw2="";
for (int y=a;y<=m;y++)
{
nw=nw+input[y];
}
for (int t=m;t>=a;t--)
{
nw2=nw2+input[t];
}
if(nw2.equals(nw))
{
out.add(nw);
break;
}
}
}
}
int a = out.size();
int maxpos=0;
int max=0;
Object [] s = out.toArray();
for(int q=0;q<a;q++)
{
if(max<s[q].toString().length())
{
max=s[q].toString().length();
maxpos=q;
}
}
String output = "longest palindrome is : "+s[maxpos].toString()+" and the lengths is : "+ max;
return output;
}
this method will return the max length palindrome and the length of it. its a way that i tried and got the answer. and this method will run whether its a odd length or even length.

Java compressing Strings

I need to create a method that receives a String and also returns a String.
Ex input: AAABBBBCC
Ex output: 3A4B2C
Well, this is quite embarrassing and I couldn't manage to do it on the interview that I had today ( I was applying for a Junior position ), now, trying at home I made something that works statically, I mean, not using a loop which is kind of useless but I don't know if I'm not getting enough hours of sleep or something but I can't figure it out how my for loop should look like. This is the code:
public static String Comprimir(String texto){
StringBuilder objString = new StringBuilder();
int count;
char match;
count = texto.substring(texto.indexOf(texto.charAt(1)), texto.lastIndexOf(texto.charAt(1))).length()+1;
match = texto.charAt(1);
objString.append(count);
objString.append(match);
return objString.toString();
}
Thanks for your help, I'm trying to improve my logic skills.
Loop through the string remembering what you last saw. Every time you see the same letter count. When you see a new letter put what you have counted onto the output and set the new letter as what you have last seen.
String input = "AAABBBBCC";
int count = 1;
char last = input.charAt(0);
StringBuilder output = new StringBuilder();
for(int i = 1; i < input.length(); i++){
if(input.charAt(i) == last){
count++;
}else{
if(count > 1){
output.append(""+count+last);
}else{
output.append(last);
}
count = 1;
last = input.charAt(i);
}
}
if(count > 1){
output.append(""+count+last);
}else{
output.append(last);
}
System.out.println(output.toString());
You can do that using the following steps:
Create a HashMap
For every character, Get the value from the hashmap
-If the value is null, enter 1
-else, replace the value with (value+1)
Iterate over the HashMap and keep concatenating (Value+Key)
use StringBuilder (you did that)
define two variables - previousChar and counter
loop from 0 to str.length() - 1
each time get str.charat(i) and compare it to what's stored in the previousChar variable
if the previous char is the same, increment a counter
if the previous char is not the same, and counter is 1, increment counter
if the previous char is not the same, and counter is >1, append counter + currentChar, reset counter
after the comparison, assign the current char previousChar
cover corner cases like "first char"
Something like that.
The easiest approach:- Time Complexity - O(n)
public static void main(String[] args) {
String str = "AAABBBBCC"; //input String
int length = str.length(); //length of a String
//Created an object of a StringBuilder class
StringBuilder sb = new StringBuilder();
int count=1; //counter for counting number of occurances
for(int i=0; i<length; i++){
//if i reaches at the end then append all and break the loop
if(i==length-1){
sb.append(str.charAt(i)+""+count);
break;
}
//if two successive chars are equal then increase the counter
if(str.charAt(i)==str.charAt(i+1)){
count++;
}
else{
//else append character with its count
sb.append(str.charAt(i)+""+count);
count=1; //reseting the counter to 1
}
}
//String representation of a StringBuilder object
System.out.println(sb.toString());
}
In the count=... line, lastIndexOf will not care about consecutive values, and will just give the last occurence.
For instance, in the string "ABBA", the substring would be the whole string.
Also, taking the length of the substring is equivalent to subtracting the two indexes.
I really think that you need a loop.
Here is an example :
public static String compress(String text) {
String result = "";
int index = 0;
while (index < text.length()) {
char c = text.charAt(index);
int count = count(text, index);
if (count == 1)
result += "" + c;
else
result += "" + count + c;
index += count;
}
return result;
}
public static int count(String text, int index) {
char c = text.charAt(index);
int i = 1;
while (index + i < text.length() && text.charAt(index + i) == c)
i++;
return i;
}
public static void main(String[] args) {
String test = "AAABBCCC";
System.out.println(compress(test));
}
Please try this one. This may help to print the count of characters which we pass on string format through console.
import java.util.*;
public class CountCharacterArray {
private static Scanner inp;
public static void main(String args[]) {
inp = new Scanner(System.in);
String str=inp.nextLine();
List<Character> arrlist = new ArrayList<Character>();
for(int i=0; i<str.length();i++){
arrlist.add(str.charAt(i));
}
for(int i=0; i<str.length();i++){
int freq = Collections.frequency(arrlist, str.charAt(i));
System.out.println("Frequency of "+ str.charAt(i)+ " is: "+freq);
}
}
}
Java's not my main language, hardly ever use it, but I wanted to give it a shot :]
Not even sure if your assignment requires a loop, but here's a regexp approach:
public static String compress_string(String inp) {
String compressed = "";
Pattern pattern = Pattern.compile("([\\w])\\1*");
Matcher matcher = pattern.matcher(inp);
while(matcher.find()) {
String group = matcher.group();
if (group.length() > 1) compressed += group.length() + "";
compressed += group.charAt(0);
}
return compressed;
}
This is just one more way of doing it.
public static String compressor(String raw) {
StringBuilder builder = new StringBuilder();
int counter = 0;
int length = raw.length();
int j = 0;
while (counter < length) {
j = 0;
while (counter + j < length && raw.charAt(counter + j) == raw.charAt(counter)) {
j++;
}
if (j > 1) {
builder.append(j);
}
builder.append(raw.charAt(counter));
counter += j;
}
return builder.toString();
}
The following can be used if you are looking for a basic solution. Iterate through the string with one element and after finding all the element occurrences, remove that character. So that it will not interfere in the next search.
public static void main(String[] args) {
String string = "aaabbbbbaccc";
int counter;
String result="";
int i=0;
while (i<string.length()){
counter=1;
for (int j=i+1;j<string.length();j++){
System.out.println("string length ="+string.length());
if (string.charAt(i) == string.charAt(j)){
counter++;
}
}
result = result+string.charAt(i)+counter;
string = string.replaceAll(String.valueOf(string.charAt(i)), "");
}
System.out.println("result is = "+result);
}
And the output will be :=
result is = a4b5c3
private String Comprimir(String input){
String output="";
Map<Character,Integer> map=new HashMap<Character,Integer>();
for(int i=0;i<input.length();i++){
Character character=input.charAt(i);
if(map.containsKey(character)){
map.put(character, map.get(character)+1);
}else
map.put(character, 1);
}
for (Entry<Character, Integer> entry : map.entrySet()) {
output+=entry.getValue()+""+entry.getKey().charValue();
}
return output;
}
One other simple way using Multiset of guava-
import java.util.Arrays;
import com.google.common.collect.HashMultiset;
import com.google.common.collect.Multiset;
import com.google.common.collect.Multiset.Entry;
public class WordSpit {
public static void main(String[] args) {
String output="";
Multiset<String> wordsMultiset = HashMultiset.create();
String[] words="AAABBBBCC".split("");
wordsMultiset.addAll(Arrays.asList(words));
for (Entry<String> string : wordsMultiset.entrySet()) {
if(!string.getElement().isEmpty())
output+=string.getCount()+""+string.getElement();
}
System.out.println(output);
}
}
consider the below Solution in which the String s1 identifies the unique characters that are available in a given String s (for loop 1), in the second for loop build a string s2 that contains unique character and no of times it is repeated by comparing string s1 with s.
public static void main(String[] args)
{
// TODO Auto-generated method stub
String s = "aaaabbccccdddeee";//given string
String s1 = ""; // string to identify how many unique letters are available in a string
String s2=""; //decompressed string will be appended to this string
int count=0;
for(int i=0;i<s.length();i++) {
if(s1.indexOf(s.charAt(i))<0) {
s1 = s1+s.charAt(i);
}
}
for(int i=0;i<s1.length();i++) {
for(int j=0;j<s.length();j++) {
if(s1.charAt(i)==s.charAt(j)) {
count++;
}
}
s2=s2+s1.charAt(i)+count;
count=0;
}
System.out.println(s2);
}
It may help you.
public class StringCompresser
{
public static void main(String[] args)
{
System.out.println(compress("AAABBBBCC"));
System.out.println(compress("AAABC"));
System.out.println(compress("A"));
System.out.println(compress("ABBDCC"));
System.out.println(compress("AZXYC"));
}
static String compress(String str)
{
StringBuilder stringBuilder = new StringBuilder();
char[] charArray = str.toCharArray();
int count = 1;
char lastChar = 0;
char nextChar = 0;
lastChar = charArray[0];
for (int i = 1; i < charArray.length; i++)
{
nextChar = charArray[i];
if (lastChar == nextChar)
{
count++;
}
else
{
stringBuilder.append(count).append(lastChar);
count = 1;
lastChar = nextChar;
}
}
stringBuilder.append(count).append(lastChar);
String compressed = stringBuilder.toString();
return compressed;
}
}
Output:
3A4B2C
3A1B1C
1A
1A2B1D2C
1A1Z1X1Y1C
The answers which used Map will not work for cases like aabbbccddabc as in that case the output should be a2b3c2d2a1b1c1.
In that case this implementation can be used :
private String compressString(String input) {
String output = "";
char[] arr = input.toCharArray();
Map<Character, Integer> myMap = new LinkedHashMap<>();
for (int i = 0; i < arr.length; i++) {
if (i > 0 && arr[i] != arr[i - 1]) {
output = output + arr[i - 1] + myMap.get(arr[i - 1]);
myMap.put(arr[i - 1], 0);
}
if (myMap.containsKey(arr[i])) {
myMap.put(arr[i], myMap.get(arr[i]) + 1);
} else {
myMap.put(arr[i], 1);
}
}
for (Character c : myMap.keySet()) {
if (myMap.get(c) != 0) {
output = output + c + myMap.get(c);
}
}
return output;
}
O(n) approach
No need for hashing. The idea is to find the first Non-matching character.
The count of each character would be the difference in the indices of both characters.
for a detailed answer: https://stackoverflow.com/a/55898810/7972621
The only catch is that we need to add a dummy letter so that the comparison for
the last character is possible.
private static String compress(String s){
StringBuilder result = new StringBuilder();
int j = 0;
s = s + '#';
for(int i=1; i < s.length(); i++){
if(s.charAt(i) != s.charAt(j)){
result.append(i-j);
result.append(s.charAt(j));
j = i;
}
}
return result.toString();
}
The code below will ask the user for user to input a specific character to count the occurrence .
import java.util.Scanner;
class CountingOccurences {
public static void main(String[] args) {
Scanner inp = new Scanner(System.in);
String str;
char ch;
int count=0;
System.out.println("Enter the string:");
str=inp.nextLine();
System.out.println("Enter th Char to see the occurence\n");
ch=inp.next().charAt(0);
for(int i=0;i<str.length();i++)
{
if(str.charAt(i)==ch)
{
count++;
}
}
System.out.println("The Character is Occuring");
System.out.println(count+"Times");
}
}
public static char[] compressionTester( char[] s){
if(s == null){
throw new IllegalArgumentException();
}
HashMap<Character, Integer> map = new HashMap<>();
for (int i = 0 ; i < s.length ; i++) {
if(!map.containsKey(s[i])){
map.put(s[i], 1);
}
else{
int value = map.get(s[i]);
value++;
map.put(s[i],value);
}
}
String newer="";
for( Character n : map.keySet()){
newer = newer + n + map.get(n);
}
char[] n = newer.toCharArray();
if(s.length > n.length){
return n;
}
else{
return s;
}
}
package com.tell.datetime;
import java.util.Stack;
public class StringCompression {
public static void main(String[] args) {
String input = "abbcccdddd";
System.out.println(compressString(input));
}
public static String compressString(String input) {
if (input == null || input.length() == 0)
return input;
String finalCompressedString = "";
String lastElement="";
char[] charArray = input.toCharArray();
Stack stack = new Stack();
int elementCount = 0;
for (int i = 0; i < charArray.length; i++) {
char currentElement = charArray[i];
if (i == 0) {
stack.push((currentElement+""));
continue;
} else {
if ((currentElement+"").equalsIgnoreCase((String)stack.peek())) {
stack.push(currentElement + "");
if(i==charArray.length-1)
{
while (!stack.isEmpty()) {
lastElement = (String)stack.pop();
elementCount++;
}
finalCompressedString += lastElement + "" + elementCount;
}else
continue;
}
else {
while (!stack.isEmpty()) {
lastElement = (String)stack.pop();
elementCount++;
}
finalCompressedString += lastElement + "" + elementCount;
elementCount=0;
stack.push(currentElement+"");
}
}
}
if (finalCompressedString.length() >= input.length())
return input;
else
return finalCompressedString;
}
}
public class StringCompression {
public static void main(String[] args){
String s = "aabcccccaaazdaaa";
char check = s.charAt(0);
int count = 0;
for(int i=0; i<s.length(); i++){
if(s.charAt(i) == check) {
count++;
if(i==s.length()-1){
System.out.print(s.charAt(i));
System.out.print(count);
}
} else {
System.out.print(s.charAt(i-1));
System.out.print(count);
check = s.charAt(i);
count = 1;
if(i==s.length()-1){
System.out.print(s.charAt(i));
System.out.print(count);
}
}
}
}
// O(N) loop through entire character array
// match current char with next one, if they matches count++
// if don't then just append current char and counter value and then reset counter.
// special case is the last characters, for that just check if count value is > 0, if it's then append the counter value and the last char
private String compress(String str) {
char[] c = str.toCharArray();
String newStr = "";
int count = 1;
for (int i = 0; i < c.length - 1; i++) {
int j = i + 1;
if (c[i] == c[j]) {
count++;
} else {
newStr = newStr + c[i] + count;
count = 1;
}
}
// this is for the last strings...
if (count > 0) {
newStr = newStr + c[c.length - 1] + count;
}
return newStr;
}
public class StringCompression {
public static void main(String... args){
String s="aabbcccaa";
//a2b2c3a2
for(int i=0;i<s.length()-1;i++){
int count=1;
while(i<s.length()-1 && s.charAt(i)==s.charAt(i+1)){
count++;
i++;
}
System.out.print(s.charAt(i));
System.out.print(count);
}
System.out.println(" ");
}
}
This is a leet code problem 443. Most of the answers here uses StringBuilder or a HashMap, the actual problem statement is to solve using the input char array and in place array modification.
public int compress(char[] chars) {
int startIndex = 0;
int lastArrayIndex = 0;
if (chars.length == 1) {
return 1;
}
if (chars.length == 0) {
return 0;
}
for (int j = startIndex + 1; j < chars.length; j++) {
if (chars[startIndex] != chars[j]) {
chars[lastArrayIndex] = chars[startIndex];
lastArrayIndex++;
if ((j - startIndex) > 1) {
for (char c : String.valueOf(j - startIndex).toCharArray()) {
chars[lastArrayIndex] = c;
lastArrayIndex++;
}
}
startIndex = j;
}
if (j == chars.length - 1) {
if (j - startIndex >= 1) {
j = chars.length;
chars[lastArrayIndex] = chars[startIndex];
lastArrayIndex++;
for (char c : String.valueOf(j - startIndex).toCharArray()) {
chars[lastArrayIndex] = c;
lastArrayIndex++;
}
} else {
chars[lastArrayIndex] = chars[startIndex];
lastArrayIndex++;
}
}
}
return lastArrayIndex;
}
}

Categories

Resources