LZW Compression/ Expansion in Java - java

I am trying to use the LZW code provided by Princeton and modify it to vary the size of codeword from 9 to 16 bits. I am unsure of how to do this, but was thinking of maybe using a loop since the size needs to be increased when all codewords of the size before were used. I am just looking for a useful direction to go in, since this is an assignment that I am having trouble starting.
public class LZW {
private static final int R = 256; // number of input chars
private static final int L = 4096; // number of codewords = 2^W
private static final int W = 12; // codeword width
public static void compress() {
String input = BinaryStdIn.readString();
TST<Integer> st = new TST<Integer>();
for (int i = 0; i < R; i++)
st.put("" + (char) i, i);
int code = R+1; // R is codeword for EOF
while (input.length() > 0) {
String s = st.longestPrefixOf(input); // Find max prefix match s.
BinaryStdOut.write(st.get(s), W); // Print s's encoding.
int t = s.length();
if (t < input.length() && code < L) // Add s to symbol table.
st.put(input.substring(0, t + 1), code++);
input = input.substring(t); // Scan past s in input.
}
BinaryStdOut.write(R, W);
BinaryStdOut.close();
}
public static void expand() {
String[] st = new String[L];
int i; // next available codeword value
// initialize symbol table with all 1-character strings
for (i = 0; i < R; i++)
st[i] = "" + (char) i;
st[i++] = ""; // (unused) lookahead for EOF
int codeword = BinaryStdIn.readInt(W);
if (codeword == R) return; // expanded message is empty string
String val = st[codeword];
while (true) {
BinaryStdOut.write(val);
codeword = BinaryStdIn.readInt(W);
if (codeword == R) break;
String s = st[codeword];
if (i == codeword) s = val + val.charAt(0); // special case hack
if (i < L) st[i++] = val + s.charAt(0);
val = s;
}
BinaryStdOut.close();
}
public static void main(String[] args) {
if (args[0].equals("-")) compress();
else if (args[0].equals("+")) expand();
else throw new IllegalArgumentException("Illegal command line argument");
}
}

Related

Trying to determine how to read input from console that could be over 10,000 characters in length

I'm currently trying determine how to use bufferedreader to read from a console program. I know the correct syntax to read from the console and I know the program is working for smaller text. However, any text greater than 5118 characters will be truncated. The console itself will also not print out any text greater than 5118 characters. The goal is to create a java program that will read from the console independent of the size of data being read.
The following is the code I have created.
package countAnagrams;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.*;
public class TestClass {
public static int check_For_Missing_Characters(String a1, String b1){
int first_String_Length = a1.length();
int missing_Characters = 0;
for( int y = 0; y < first_String_Length; y++ ){
final char character_To_Check_String = a1.charAt(y);
if ( b1.chars().filter(ch -> ch ==
character_To_Check_String).count() == 0 ){
missing_Characters+=1;
}
}
return missing_Characters;
}
public static int check_For_Duplicate_Characters(String a1, String
b1){
int first_String_Length = a1.length();
int duplicat_Characters = 0;
String found_Characters = "";
for( int y = 0; y < first_String_Length; y++ ){
final char current_Character_To_Check = a1.charAt(y);
long first_String_Count = b1.chars().filter(ch -> ch ==
current_Character_To_Check).count();
long second_String_Count = a1.chars().filter(ch -> ch ==
current_Character_To_Check).count();
long found_String_Count = found_Characters.chars().filter(ch -> ch == current_Character_To_Check).count();
if ( first_String_Count > 0 && second_String_Count > 0 && found_String_Count == 0 ){
duplicat_Characters+=Math.abs(first_String_Count - second_String_Count);
found_Characters = found_Characters +
current_Character_To_Check;
}
}
return duplicat_Characters;
}
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int test_Case_Count = Integer.parseInt(br.readLine()); //
Reading input from STDIN
for(int x = 0; x < test_Case_Count; x++ ){
int total_Count_Of_Diff_Chars = 0;
StringBuilder first_StringBuilder = new StringBuilder();
int first_String = '0';
while(( first_String = br.read()) != -1 ) {
first_StringBuilder.append((char) first_String );
}
StringBuilder second_StringBuilder = new StringBuilder();
String second_String = "";
while((( second_String = br.readLine()) != null )){
second_StringBuilder.append(second_String);
}
total_Count_Of_Diff_Chars = total_Count_Of_Diff_Chars +
check_For_Missing_Characters(first_StringBuilder.toString(),
second_StringBuilder.toString());
total_Count_Of_Diff_Chars = total_Count_Of_Diff_Chars +
check_For_Missing_Characters(second_StringBuilder.toString(),
first_StringBuilder.toString());
total_Count_Of_Diff_Chars = total_Count_Of_Diff_Chars +
check_For_Duplicate_Characters(second_StringBuilder.toString(),
first_StringBuilder.toString());
System.out.println(total_Count_Of_Diff_Chars);
}
br.close();
}
}
The above code will work for input that is less than 5118 characters. I would like to understand what is need to make it read beyond the 5118 limit. I'm not sure if the page, I using is causing the limit or there is something that I'm missing. Remember this is also written in java code.

Replace while loop with lambda

I'm learning lambdas and I have an exercise to rewrite the while loop in this code using lambdas. This method gets encoded user input and returns decoded. I faced this problem and can't understand what I'm supposed to do. (I know that it's not hard, but I just can't get the concept.) I didn't find any similar questions here.
p.s. Also, one more qustion - can this while loop( or maybe whole method) be reworked with method reference?
public String decode(String input) {
StringBuilder letters = new StringBuilder();
input = input.toUpperCase();
int i = 0, j = 0;
while (i < input.length()) {
char symbol = input.charAt(i);
char keySymbol = KEY.charAt(j);
int newIndex = (ALPHABET.indexOf(symbol) - ALPHABET.indexOf(keySymbol)) % ALPHABET.length();
char newSymbol = ALPHABET.charAt(newIndex);
letters.append(newSymbol);
j = ++j % KEY.length();
i++;
}
return letters.toString().toLowerCase();
}
The code sample below includes the original decode method, and a new decodeLamda method.
The decodeLambda method replaces the iteration over 'input'. Running the sample will show they both have the same output. It is possible to change the loop to a method reference.
public class Main {
public static void main(String[] args) {
Main main = new Main();
System.out.println(main.decode("SECRET MESSAGE"));
System.out.println(main.decodeLambda("SECRET MESSAGE"));
}
public static String KEY = "HOPSCOTCH";
public static String ALPHABET = "ABCDEFGHIJKLMONOPQRSTUVWXYZ";
public String decode(String input) {
StringBuilder letters = new StringBuilder();
input = input.toUpperCase();
int i = 0, j = 0;
while (i < input.length()) {
char symbol = input.charAt(i);
char keySymbol = KEY.charAt(j);
int newIndex = Math.abs(ALPHABET.indexOf(symbol) - ALPHABET.indexOf(keySymbol)) % ALPHABET.length();
char newSymbol = ALPHABET.charAt(newIndex);
letters.append(newSymbol);
j = ++j % KEY.length();
i++;
}
return letters.toString().toLowerCase();
}
public String decodeLambda(String input) {
StringBuilder letters = new StringBuilder();
input = input.toUpperCase();
var ref = new Object() {
int j = 0;
};
input.chars()
.forEach( symbol -> {
char keySymbol = KEY.charAt(ref.j);
int newIndex = Math.abs(ALPHABET.indexOf(symbol) - ALPHABET.indexOf(keySymbol)) % ALPHABET.length();
char newSymbol = ALPHABET.charAt(newIndex);
letters.append(newSymbol);
ref.j = ++ref.j % KEY.length();
});
return letters.toString().toLowerCase();
}
}

How to use/modify Knuth-Morris-Pratt algorithm to convert any given string to palindrome

I have been given a task to create a class that given a String will create a palindrome with minimum number of assertions.
Example Runs:
Input: 123333
Output: 12333321
Input: 789
Output: 78987
Input: 1221
Output: 1221221
**Note a Palindrome should NOT return the same Palindrome.
I tried using a modified KMP algorithm as stated here.
I revert the string and compare it to the reverse + original string and then add the mismatches to the original string.
However my function only works for inputs with trailing digits (first example input) however an input like 1234 will return 1234123, '92837465' will return '928374659283746'
public static int[] computelps(String sample){
int[] lps = new int[sample.length()];
lps[0] = 0;
int i = 1;
int len = 0; // length of previous longest prefix suffix
while (i < sample.length()) {
if (sample.charAt(i) == sample.charAt(len)) {
len++;
lps[i] = len;
i++;
}
else
{
if (len != 0) {
len = lps[len - 1];
}
else {
lps[i] = 0;
i++;
}
}
}
return lps;
}
public static void Solution(File samplefile) throws Exception {
BufferedReader br = new BufferedReader(new FileReader(samplefile));
String firstline = br.readLine();
String line;
while ((line = br.readLine()) != null) {
String reverse_str = "";
String newline = line.replace(".", "");
for (int i = newline.length() - 1; i >= 0; i--) {
reverse_str += newline.charAt(i);
}
int [] lps = computelps(reverse_str); // computes the lps of the pattern string
String tot = reverse_str + newline;
// KMP Algorithm modified.
int x = 0; // index for total_string(tot)
int y = 0; // index for pattern
String palindrome = newline;
while (x < tot.length()){
if(reverse_str.charAt(y) == tot.charAt(x)){
y++;
x++;
}
if(y == reverse_str.length()) {
y = lps[y - 1];
}
else if( x < tot.length() && (reverse_str.charAt(y) != tot.charAt(x))){
palindrome += tot.charAt(x);
if ( y!= 0){
y = lps[y-1];
}
else{
x += 1;
}
}
}
System.out.println(palindrome);
}
}
I would appreciate any help. I find algorithms very challenging so please bear with me if my approach or code is sub-par.
*I fixed sample inputs and outputs as well as added my results.
It helps to split this problem in smaller problems, implement a separate method for each and check to see if each method works as expected. What will really help you will be to learn to use the debugger in your Ide. But until you do that you can test that each part of your code works as expected. So I simplified a little your code and split it up :
public static void main(String[] args){
System.out.println("computelps " + ("[0, 0, 0, 0]".equals(Arrays.toString(computelps("4321"))) ? "works" : "doesn't work" ));
System.out.println("reverse " + ("4321".equals(reverse("1234")) ? "works" : "doesn't work" ));
System.out.println("Solution " + ("1234321".equals(Solution("1234")) ? "works" : "doesn't work" ));
}
public static int[] computelps(String sample){
int[] lps = new int[sample.length()];
lps[0] = 0;
int i = 1;
int len = 0; // length of previous longest prefix suffix
while (i < sample.length()) {
if (sample.charAt(i) == sample.charAt(len)) {
len++;
lps[i] = len;
i++;
}
else
{
if (len != 0) {
len = lps[len - 1];
}
else {
lps[i] = 0;
i++;
}
}
}
return lps;
}
public static String Solution(String line) {
String newline = line.replace(".", "");
String reverse_str = reverse(newline);
int [] lps = computelps(reverse_str); // computes the lps of the pattern string
// KMP Algorithm modified.
return kpmModified(newline, reverse_str, lps);
}
private static String kpmModified(String newline, String reverse_str, int[] lps) {
int x = 0; // index for total_string(tot)
int y = 0; // index for pattern
String tot = reverse_str + newline;
String palindrome = newline;
while (x < tot.length()){
if(reverse_str.charAt(y) == tot.charAt(x)){
y++;
x++;
}
if(y == reverse_str.length()) {
y = lps[y - 1];
}
else if( x < tot.length() && (reverse_str.charAt(y) != tot.charAt(x))){
palindrome += tot.charAt(x);
if ( y!= 0){
y = lps[y-1];
}
else{
x += 1;
}
}
}
return palindrome;
}
private static String reverse(String newline) {
String reverse_str = "";
for (int i = newline.length() - 1; i >= 0; i--) {
reverse_str += newline.charAt(i);
}
return reverse_str;
}
And the result is
computelps works
reverse works
Solution doesn't work
So your bug is in kpmModified method. I can't spend more time and I'm not familiar with the algorithm but you should continue like this and figure our what part of that method has the bug.
I think you overthink the problem. The question is basically adding a string's reversed version back to it's original, but not every character, right? So you might need to find something like a pointer to tell the function where to start to reverse.
One example. Let the string be 12333. If we add every character from the index string.length() to 0, it will be 1233333321, which is not correct, since there are duplicated 3's. We need to ignore those, so we need to add characters from string.length() - numOfDuplicateAtEnd to 0.
public String palindromic(String num) {
int i = num.length() - 1;
while (i > -1 && num.charAt(i) == num.charAt(num.length() - 1))
i--;
for (int k = i; k > -1; --k)
num += num.substring(k, k + 1);
return num;
}

System.out.print() not printing to terminal

This may be a very stupid question but I am trying to modify provided code from Sedgewick's "Algorithms" textbook for a class project. For debugging purposes I just want to print out some information to terminal at various points. Not matter where I insert System.out.println("testing") for example, I recieve no errors and the program runs to completion but nothing was ever printed out. Is it possible that the target destination for printing is not terminal for some reason?
public class LZW {
private static final int R = 256; // number of input chars
private static final int L = 4096; // number of codewords = 2^W
private static final int W = 12; // codeword width
public static void compress() {
String input = BinaryStdIn.readString();
TST<Integer> st = new TST<Integer>();
for (int i = 0; i < R; i++)
st.put("" + (char) i, i);
int code = R+1; // R is codeword for EOF
while (input.length() > 0) {
String s = st.longestPrefixOf(input); // Find max prefix match s.
BinaryStdOut.write(st.get(s), W); // Print s's encoding.
int t = s.length();
if (t < input.length() && code < L) // Add s to symbol table.
st.put(input.substring(0, t + 1), code++);
input = input.substring(t); // Scan past s in input.
}
BinaryStdOut.write(R, W);
BinaryStdOut.close();
}
public static void expand() {
String[] st = new String[L];
int i; // next available codeword value
// initialize symbol table with all 1-character strings
for (i = 0; i < R; i++)
st[i] = "" + (char) i;
st[i++] = ""; // (unused) lookahead for EOF
int codeword = BinaryStdIn.readInt(W);
if (codeword == R) return; // expanded message is empty string
String val = st[codeword];
while (true) {
BinaryStdOut.write(val);
codeword = BinaryStdIn.readInt(W);
if (codeword == R) break;
String s = st[codeword];
if (i == codeword) s = val + val.charAt(0); // special case hack
if (i < L) st[i++] = val + s.charAt(0);
val = s;
}
BinaryStdOut.close();
}
public static void main(String[] args) {
System.out.println("Testing123");
if (args[0].equals("-")) compress();
else if (args[0].equals("+")) expand();
else throw new IllegalArgumentException("Illegal command line argument");
}
}

Fancy looping in Java

I have a problem wherein I have two strings, the length of one of which I will know only upon execution of my function. I want to write my function such that it would take these two stings and based upon which one is longer, compute a final string as under -
finalString = longerStringChars1AND2
+ shorterStringChar1
+ longerStringChars3and4
+ shorterStringChar2
+ longerStringChars5AND6
...and so on till the time the SHORTER STRING ENDS.
Once the shorter string ends, I want to append the remaining characters of the longer string to the final string, and exit. I have written some code, but there is too much looping for my liking. Any suggestions?
Here is the code I wrote - very basic -
public static byte [] generateStringToConvert(String a, String b){
(String b's length is always known to be 14.)
StringBuffer stringToConvert = new StringBuffer();
int longer = (a.length()>14) ? a.length() : 14;
int shorter = (longer > 14) ? 14 : a.length();
int iteratorForLonger = 0;
int iteratorForShorter = 0;
while(iteratorForLonger < longer) {
int count = 2;
while(count>0){
stringToConvert.append(b.charAt(iteratorForLonger));
iteratorForLonger++;
count--;
}
if(iteratorForShorter < shorter && iteratorForLonger >= longer){
iteratorForLonger = 0;
}
if(iteratorForShorter<shorter){
stringToConvert.append(a.charAt(iteratorForShorter));
iteratorForShorter++;
}
else{
break;
}
}
if(stringToConvert.length()<32 | iteratorForLonger<b.length()){
String remainingString = b.substring(iteratorForLonger);
stringToConvert.append(remainingString);
}
System.out.println(stringToConvert);
return stringToConvert.toString().getBytes();
}
You can use StringBuilder to achieve this. Please find below source code.
public static void main(String[] args) throws InterruptedException {
int MAX_ALLOWED_LENGTH = 14;
String str1 = "yyyyyyyyyyyyyyyy";
String str2 = "xxxxxx";
StringBuilder builder = new StringBuilder(MAX_ALLOWED_LENGTH);
builder.append(str1);
char[] shortChar = str2.toCharArray();
int index = 2;
for (int charCount = 0; charCount < shortChar.length;) {
if (index < builder.length()) {
// insert 1 character from short string to long string
builder.insert(index, shortChar, charCount, 1);
}
// 2+1 as insertion index is increased after after insertion
index = index + 3;
charCount = charCount + 1;
}
String trimmedString = builder.substring(0, MAX_ALLOWED_LENGTH);
System.out.println(trimmedString);
}
Output
yyxyyxyyxyyxyy
String one = "longwordorsomething";
String two = "short";
String shortString = "";
String longString = "";
if(one.length() > two.length()) {
shortString = two;
longString = one;
} else {
shortString = one;
longString = two;
}
StringBuilder newString = new StringBuilder();
int j = 0;
for(int i = 0; i < shortString.length(); i++) {
if((j + 2) < longString.length()) {
newString.append(longString.substring(j, j + 2));
j += 2;
}
newString.append(shortString.substring(i, i + 1));
}
// Append last part
newString.append(longString.substring(j));
System.out.println(newString);

Categories

Resources