I am trying to make a program to decompress a string that was compressed using RLE. The decompression program, however, must be written recursively, without loops, and without declaring variables outside the method. Below is my closest attempt so far, I am able to get the first "piece" of the compressed string (ex: 4w, q, g, J, 6y, etc.) decompressed. It just won't print out anything else after that, and I'm having trouble understanding why. much thanks
public class StringRec{
public static void main(String[] a){
System.out.println("string: ");
String decomp = IO.readString();
System.out.println(decompress(decomp));
}
public static String decompress(String compressedText){
int count = compressedText.length();
String index = "";
if(count == 0){
return "";
}
I though to make a few conditions that don't call the decompress method again,
because the condition for them is that they are the last piece in the string, so after their part is decompressed its done. Naturally, there calling would occur at the end of the runtime, after the other conditions with the decompress call have been called. Not sure why it isn't working.
else{
if(Character.isDigit(compressedText.charAt(0))){
String s = String.format("%0" + compressedText.charAt(0) + "d", 0).replace('0', compressedText.charAt(1));
index = s;
compressedText = compressedText.substring(2);
decompress(compressedText);
}
else if(Character.isDigit(compressedText.charAt(0)) && compressedText.length()==2){
String s2 = String.format("%0" + compressedText.charAt(0) + "d", 0).replace('0', compressedText.charAt(1));
index = s2;
}else if(Character.isLetter(compressedText.charAt(0))){
String s3 = Character.toString(compressedText.charAt(0));
index = s3;
compressedText = compressedText.substring(1);
decompress(compressedText);
}
else if(Character.isLetter(compressedText.charAt(0)) && compressedText.length()==1){
String s4 = Character.toString(compressedText.charAt(0));
index = s4;
}
return index;
}
}
My current guesses are that it has something to do with how the decompress method is called, or its a problem with how I arrange the output to be returned after the decompress method is already called, but then I wouldn't be able to explain how the first part of the string works consistently.
Try this.
public static String decompress(String compressedText) {
int count = compressedText.length();
if (count == 0) {
return "";
} else if (Character.isDigit(compressedText.charAt(0))) {
String s = String.format("%0" + compressedText.charAt(0) + "d", 0)
.replace('0', compressedText.charAt(1));
return s + decompress(compressedText.substring(2));
} else if (Character.isLetter(compressedText.charAt(0))) {
String s3 = Character.toString(compressedText.charAt(0));
return s3 + decompress(compressedText.substring(1));
} else
return compressedText;
}
It is not working because you forgot to 'concatenate' the result of the recursive decompress calls with the current index variable value. Because of this you 'drop' the results of the recursive calls and only have the result of the first call.
If you modify the decompress(compressedText) lines with index = index + decompress(compressedText) in your code, your results will be what you would expect.
(Btw, you should rename the topic to something like 'Java Recursive Decompression Program does not get the expected result' because from the title I would expect some code which produces infinite recursive calls :) )
Related
I have a long String with binary values. And i have a hash map that has the Binary digits as a key and char as a value. I have a function that supposed to read the binary string using 2 pointers and compare with hashmap and store the corresponding char in main.decodedTxt. However, im getting string out of bound exception for this. I don't know how to solve this. I'm getting exception on "String temp =" line. I have a picture link of the console output to see better picture.
public static void bitStringToText (String binText){
String bs = binText;
int from =0;
int to = 1;
while(bs != null){
String temp = bs.substring(from, to);
if (main.newMapDecoding.containsKey(temp)){
main.decodedTxt += main.newMapDecoding.get(temp);
from =to;
to = from +1;
} else {
to = to + 1;
}
}
}
Image of console exception is here
First of all there is no need to check if bs is null because no part of your code changes the value of bs. Your current code will cross the possible index of your binText at some point. It's better to loop just binText and check if you find something within it. After all you have to traverse the complete string anyways. Change your code as follows
public static void bitStringToText (String binText){
//no need to do this if you are not modifying the contents of binText
//String bs = binText;
int from =0;
int to = 1;
int size = binText.length();
String temp = "";
while(to <= size ){
temp = binText.substring(from, to);
if (main.newMapDecoding.containsKey(temp)){
main.decodedTxt += main.newMapDecoding.get(temp);
from =to;
to = from +1;
} else {
to = to + 1;
}
}
}
Hope it helps.
First, give it a try to practice debugging. It is an easy case. Either use run in debug mode (place break point on String temp = bs.substring(from, to); line) or print values of from and to before the same line. It will help to understand what is going on.
Solution:
If bs is not null you will always have StringIndexOutOfBoundsException. Because you are not checking if to is pointing to not existed index of bs String. Easiest example of the first one will be empty String: bs == "".
One of the solution could be to replace condition in while to while (to <= bs.length()).
I am trying to remove all the substrings enclosed with in square braces in a given string. I am using a while loop to process the string until there are no square braces [ and ] in the string, and i am using the substring function inside the loop. Here is the code:
public String removeSquareBraceAndEnclosedSubstring(String inputString) {
//continue until there is atleast one [ and one ]
while (inputString.indexOf('[') > 0 && inputString.indexOf(']') > 0){
int lastIndexOfOpenBrace = inputString.lastIndexOf('[');
int firstIndexOfCloseBrace = inputString.indexOf(']');
String beforeOpenBrace = inputString.substring(0, lastIndexOfOpenBrace);
String afterCloseBrace = "";
if (!inputString.endsWith("]"))
afterCloseBrace = inputString.substring(firstIndexOfCloseBrace + 1
, inputString.length());
inputString = beforeOpenBrace + afterCloseBrace ;
}
return inputString;
}
I am getting an error
java.lang.OutOfMemoryError: Java heap space
java.util.Arrays.copyOfRange(Arrays.java:2694)
java.lang.String.<init>(String.java:203)
java.lang.String.substring(String.java:1913) on calling this method
I do not want to increase the heap size to solve this. I tried making use of functions like intern(), replacing string assignment by calling String constructor. Also i tried processing using a string builder instead of a string. Nothing seems to solve the issue. Is there a better solution or approach to solve this problem?
public class Example{
public static void main(String[] args) {
String str1 = "hi [foo [bar] buzz] there [foo]";
String str2 = "this is a [sample] string [with some substrings enclosed with in square braces] yeah!";
System.out.println(removeSquareBraceAndEnclosedSubstring(str1));
System.out.println(removeSquareBraceAndEnclosedSubstring(str2));
}
public static String removeSquareBraceAndEnclosedSubstring(String inputString) {
while(inputString.contains("[")){
int openPos = inputString.indexOf('[');
inputString = inputString.substring(0,openPos)+ inputString.substring(findClosingBrace(inputString.toCharArray(), openPos)+1);
}
return inputString.replaceAll("\\s+", " ");
}
public static int findClosingBrace(char[] text, int openPos) {
int closePos = openPos;
int counter = 1;
while (counter > 0) {
char c = text[++closePos];
if (c == '[') {
counter++;
}
else if (c == ']') {
counter--;
}
}
return closePos;
}
}
Your code breaks when you have brackets beside each other like this: (numbers are index position)
012345678
[hi][bye]
This happens because you're detecting lastIndexOfOpenBrace to be at index 4; which it is. Your code is designed to remove anything that's found between the lastIndexOfOpenBrace and the firstIndexOfCloseBrace. (Basically between index 3 and 4) In this case, there's nothing to remove, and you get stuck in an infinite loop. Placing this code at the start of your while loop will remove this error.
if(inputString.contains("][")){
inputString = inputString.replace("][", "");
continue;
}
There could be more errors. I am unsure.
Your code will always break when inputstring have close braces before open braces.
you can write a condition
close bracs index should be greater than open braces index.
So recently I got invited to this google foo.bar challenge and I believe the code runs the way it should be. To be precise what I need to find is the number of occurrences of "abc" in a String. When I verify my code with them, I pass 3/10 test cases. I'm starting to feel bad because I don't know what I am doing wrong. I have written the code which I will share with you guys. Also the string needs to be less than 200 characters. When I run this from their website, I pass 3 tests and fail 7. Basically 7 things need to be right.
The actual question:
Write a function called answer(s) that, given a non-empty string less
than 200 characters in length describing the sequence of M&Ms. returns the maximum number of equal parts that can be cut from the cake without leaving any leftovers.
Example : Input : (string) s = "abccbaabccba"
output : (int) 2
Input: (string) s = "abcabcabcabc"
output : (int) 4
public static int answer(String s) {
int counter = 0;
int index;
String findWord ="ABC";
if(s!=null && s.length()<200){
s = s.toUpperCase();
while (s.contains(findWord))
{
index = s.indexOf(findWord);
s = s.substring(index + findWord.length(), s.length());
counter++;
}
}
return counter;
}
I see a couple of things in your code snippet:
1.
if(s.length()<200){
Why are you checking for the length to be lesser than 200? Is that a requirement? If not, you can skip checking the length.
2.
String findWord ="abc";
...
s.contains(findWord)
Can the test program be checking for upper case alphabets? Example: "ABC"? If so, you might need to consider changing your logic for the s.contains() line.
Update:
You should also consider putting a null check for the input string. This will ensure that the test cases will not fail for null inputs.
The logic of your code is well but on the other hand i found that you didn't check for if input string is empty or null.
I belief that google foo.bar wants to see the logic and the way of coding in a proper manner.
so don't be feel bad
I would go for a simpler approach
int beforeLen = s.length ();
String after = s.replace (findWord, "");
int afterLen = after.length ();
return (beforeLen - afterLen) / findWord.length ();
String pattern = "abc";
String line="<input text here>";
int i=0;
Pattern TokenPattern=Pattern.compile(pattern);
if(line!=null){
Matcher m=TokenPattern.matcher(line);
while(m.find()){
i++;
}}
System.out.println("No of occurences : "+ " "+i);
put declaration of index out before while block, isn't never good re-declare the same variable n time.
int index;
while (s.contains(findWord))
{
index = s.indexOf(findWord);
....
}
I hope this help
Update:
try to compact your code
public static int answer(String s) {
int counter = 0;
int index;
String findWord = "ABC";
if (s != null && s.length() < 200) {
s = s.toUpperCase();
while ((index = s.indexOf(findWord)) > -1) {
s = s.substring(index + findWord.length(), s.length());
counter++;
}
}
return counter;
}
Update:
The logic seems good to me, I'm still try to improve the performance, if you can try this
while ((index = s.indexOf(findWord, index)) > -1) {
//s = s.substring(index + findWord.length(), s.length());
index+=findWord.length();
counter++;
}
I'm using codingbat.com to get some java practice in. One of the String problems, 'withoutString' is as follows:
Given two strings, base and remove, return a version of the base string where all instances of the remove string have been removed (not case sensitive).
You may assume that the remove string is length 1 or more. Remove only non-overlapping instances, so with "xxx" removing "xx" leaves "x".
This problem can be found at: http://codingbat.com/prob/p192570
As you can see from the the dropbox-linked screenshot below, all of the runs pass except for three and a final one called "other tests." The thing is, even though they are marked as incorrect, my output matches exactly the expected output for the correct answer.
Here's a screenshot of my output:
And here's the code I'm using:
public String withoutString(String base, String remove) {
String result = "";
int i = 0;
for(; i < base.length()-remove.length();){
if(!(base.substring(i,i+remove.length()).equalsIgnoreCase(remove))){
result = result + base.substring(i,i+1);
i++;
}
else{
i = i + remove.length();
}
if(result.startsWith(" ")) result = result.substring(1);
if(result.endsWith(" ") && base.substring(i,i+1).equals(" ")) result = result.substring(0,result.length()-1);
}
if(base.length()-i <= remove.length() && !(base.substring(i).equalsIgnoreCase(remove))){
result = result + base.substring(i);
}
return result;
}
Your solution IS failing AND there is a display bug in coding bat.
The correct output should be:
withoutString("This is a FISH", "IS") -> "Th a FH"
Yours is:
withoutString("This is a FISH", "IS") -> "Th a FH"
Yours fails because it is removing spaces, but also, coding bat does not display the correct expected and run output string due to HTML removing extra spaces.
This recursive solution passes all tests:
public String withoutString(String base, String remove) {
int remIdx = base.toLowerCase().indexOf(remove.toLowerCase());
if (remIdx == -1)
return base;
return base.substring(0, remIdx ) +
withoutString(base.substring(remIdx + remove.length()) , remove);
}
Here is an example of an optimal iterative solution. It has more code than the recursive solution but is faster since far fewer function calls are made.
public String withoutString(String base, String remove) {
int remIdx = 0;
int remLen = remove.length();
remove = remove.toLowerCase();
while (true) {
remIdx = base.toLowerCase().indexOf(remove);
if (remIdx == -1)
break;
base = base.substring(0, remIdx) + base.substring(remIdx + remLen);
}
return base;
}
I just ran your code in an IDE. It compiles correctly and matches all tests shown on codingbat. There must be some bug with codingbat's test cases.
If you are curious, this problem can be solved with a single line of code:
public String withoutString(String base, String remove) {
return base.replaceAll("(?i)" + remove, ""); //String#replaceAll(String, String) with case insensitive regex.
}
Regex explaination:
The first argument taken by String#replaceAll(String, String) is what is known as a Regular Expression or "regex" for short.
Regex is a powerful tool to perform pattern matching within Strings. In this case, the regular expression being used is (assuming that remove is equal to IS):
(?i)IS
This particular expression has two parts: (?i) and IS.
IS matches the string "IS" exactly, nothing more, nothing less.
(?i) is simply a flag to tell the regex engine to ignore case.
With (?i)IS, all of: IS, Is, iS and is will be matched.
As an addition, this is (almost) equivalent to the regular expressions: (IS|Is|iS|is), (I|i)(S|s) and [Ii][Ss].
EDIT
Turns out that your output is not correct and is failing as expected. See: dansalmo's answer.
public String withoutString(String base, String remove) {
String temp = base.replaceAll(remove, "");
String temp2 = temp.replaceAll(remove.toLowerCase(), "");
return temp2.replaceAll(remove.toUpperCase(), "");
}
Please find below my solution
public String withoutString(String base, String remove) {
final int rLen=remove.length();
final int bLen=base.length();
String op="";
for(int i = 0; i < bLen;)
{
if(!(i + rLen > bLen) && base.substring(i, i + rLen).equalsIgnoreCase(remove))
{
i +=rLen;
continue;
}
op += base.substring(i, i + 1);
i++;
}
return op;
}
Something things go really weird on codingBat this is just one of them.
I am adding to a previous solution, but using a StringBuilder for better practice. Most credit goes to Anirudh.
public String withoutString(String base, String remove) {
//create a constant integer the size of remove.length();
final int rLen=remove.length();
//create a constant integer the size of base.length();
final int bLen=base.length();
//Create an empty string;
StringBuilder op = new StringBuilder();
//Create the for loop.
for(int i = 0; i < bLen;)
{
//if the remove string lenght we are looking for is not less than the base length
// and the base substring equals the remove string.
if(!(i + rLen > bLen) && base.substring(i, i + rLen).equalsIgnoreCase(remove))
{
//Increment by the remove length, and skip adding it to the string.
i +=rLen;
continue;
}
//else, we add the character at i to the string builder.
op.append(base.charAt(i));
//and increment by one.
i++;
}
//We return the string.
return op.toString();
}
Taylor's solution is the most efficient one, however I have another solution that is a naive one and it works.
public String withoutString(String base, String remove) {
String returnString = base;
while(returnString.toLowerCase().indexOf(remove.toLowerCase())!=-1){
int start = returnString.toLowerCase().indexOf(remove.toLowerCase());
int end = remove.length();
returnString = returnString.substring(0, start) + returnString.substring(start+end);
}
return returnString;
}
#Daemon
your code works. Thanks for the regex explanation. Though dansalmo pointed out that codingbat is displaying the intended output incorrectly, I through in some extra lines to your code to unnecessarily account for the double spaces with the following:
public String withoutString(String base, String remove){
String result = base.replaceAll("(?i)" + remove, "");
for(int i = 0; i < result.length()-1;){
if(result.substring(i,i+2).equals(" ")){
result = result.replace(result.substring(i,i+2), " ");
}
else i++;
}
if(result.startsWith(" ")) result = result.substring(1);
return result;
}
public String withoutString(String base, String remove){
return base.replace(remove,"");
}
I'm working on an expression tree project at the moment that takes in a postfix expression from the user(i.e, 7 8 +) and stores it in an expression tree; the program should then print the tree in a typical tree format and present the user with the option to print out an infix, prefix, or postfix format.
As of now, it seems my tree is being properly instantiated, but every time I try to print it the format is slightly off and each operator/operand is duplicated. So, if the output should look like
-
6 5
it ends up looking like
- -
6 5 6 5
On top of that, whenever I try to print out an infix/prefix/postfix format, I run into several null pointer exceptions - and the way I wrote the code, I don't know how that is even possible.
The main method for printing out the tree is as follows:
public String toString() {
String result = "";
int printDepth = getHeight();
int possibleNodes = (int)Math.pow(2, printDepth+1);
int countNodes = 0;
UnorderedListADT<BTNode<ExpressionTreeNode>> nodes = new UnorderedList<BTNode<ExpressionTreeNode>>();
UnorderedListADT<Integer> levelList = new UnorderedList<Integer>();
BTNode<ExpressionTreeNode> current;
nodes.addToRear(root);
Integer currentLevel = 0;
Integer previousLevel = -1;
levelList.addToRear(currentLevel);
while(countNodes < possibleNodes) {
countNodes += 1;
current = nodes.removeFirst();
currentLevel = levelList.removeFirst();
if(currentLevel>previousLevel) {
result += "\n\n";
previousLevel = currentLevel;
for(int a=0;a<((Math.pow(2, (printDepth-currentLevel+1))-1));a++) {
result += " ";
}
}
if(current!=null) {
result += (current.getElement()).toString()+" ";
nodes.addToRear(current.getLeft());
levelList.addToRear(currentLevel+1);
nodes.addToRear(current.getRight());
levelList.addToRear(currentLevel+1);
}
else {
nodes.addToRear(null);
levelList.addToRear(currentLevel+1);
nodes.addToRear(null);
levelList.addToRear(currentLevel+1);
result += " ";
}
}
return result;
}
and the method for printing out the tree in various other formats...
public String printInorder() {
String result = "";
if(getLeft()!=null)
getLeft().printInorder();
result+= root.getElement()+" ";
if(getRight()!=null)//one null pointer occurs here
getRight().printInorder();//another occurs here
return result;
}
The methods for preorder and postorder are pretty much the same, they just change the order of result+=root.getElement()+" ";
I've tried reformatting these methods in all sorts of ways, but every time I just end up getting the same errors. I know that the entire tree isn't null, but what am I missing?
Any help would be greatly appreciated.