0

My goal is to write a program that compresses a string, for example:

input: hellooopppppp!
output:he2l3o6p!

Here is the code I have so far, but there are errors.

When I have the input: hellooo

my code outputs: hel2l3o

instead of: he213o

the 2 is being printed in the wrong spot, but I cannot figure out how to fix this.

Also, with an input of: hello

my code outputs: hel2l

instead of: he2lo

It skips the last letter in this case all together, and the 2 is also in the wrong place, an error from my first example.

Any help is much appreciated. Thanks so much!

 public class compressionTime
{
public static void main(String [] args)
{
       System.out.println ("Enter a string");

       //read in user input
       String userString = IO.readString();

       //store length of string
       int length = userString.length();

       System.out.println(length);

       int count;
       String result = "";

        for (int i=1; i<=length; i++)
        {
            char a = userString.charAt(i-1);
            count = 1;

            if (i-2 >= 0) 
            {
                while (i<=length && userString.charAt(i-1) == userString.charAt(i-2)) 
                {
                    count++;

                    i++;
                } 
               System.out.print(count);                 
            }

            if (count==1) 

                result = result.concat(Character.toString(a));
            else 

                result = result.concat(Integer.toString(count).concat(Character.toString(a)));

        }



   IO.outputStringAnswer(result);
}

}

2
  • 3
    How would you compress 1223334444? Btw ll is the same size as 2l Commented Oct 29, 2013 at 18:33
  • 1) See comment by Peter Lawrey above and his answer bellow 2) Use StringBuilder to build a string instead of concat() 3) You can append a char without converting it toString() Commented Oct 29, 2013 at 18:39

7 Answers 7

1

I would

  • count from 0 as that is how indexes work in Java. Your code will be simpler.
  • would compare the current char to the next one. This will avoid printing the first character.
  • wouldn't compress ll as 2l as it is no smaller. Only sequences of at least 3 will help.
  • try to detect if a number 3 to 9 has been used and at least print an error.
  • use the debugger to step through the code to understand what it is doing and why it doesn't do what you think it should.
Sign up to request clarification or add additional context in comments.

Comments

1

I am doing it this way. Very simple:

public static void compressString (String string) {
    StringBuffer stringBuffer = new StringBuffer();

    for (int i = 0; i < string.length(); i++) {
        int count = 1;
        while (i + 1 < string.length()
                && string.charAt(i) == string.charAt(i + 1)) {
            count++;
            i++;
        }

        if (count > 1) {
            stringBuffer.append(count);
        }

        stringBuffer.append(string.charAt(i));
    }

    System.out.println("Compressed string: " + stringBuffer);
}

Comments

0

You can accomplish this using a nested for loops and do something simial to:

       count = 0;
       String results = "";

       for(int i=0;i<userString.length();){
           char begin = userString.charAt(i);
           //System.out.println("begin is: "+begin);

           for(int j=i+1; j<userString.length();j++){
               char next = userString.charAt(j);
               //System.out.println("next is: "+next);

               if(begin == next){
                   count++;
               }
               else{
                   System.out.println("Breaking");
                   break;
               }
           }
           i+= count+1;
           if(count>0){
               String add = begin + "";
               int tempcount = count +1;

               results+= tempcount + add;

           }
           else{
               results+= begin;
           }

           count=0;

       }

   System.out.println(results);

I tested this output with Hello and the result was He2lo also tested with hellooopppppp result he2l3o6p

Comments

0

If you don't understand how this works, you should learn regular expressions.

public String rleEncodeString(String in) {
    StringBuilder out = new StringBuilder();
    Pattern p = Pattern.compile("((\\w)\\2*)");
    Matcher m = p.matcher(in);

    while(m.find()) {
        if(m.group(1).length() > 1) {
            out.append(m.group(1).length());
        }
        out.append(m.group(2));
    }

    return out.toString();
}

Comments

0

Try something like this:

public static void main(String[] args) {
    System.out.println("Enter a string:");
    Scanner IO = new Scanner(System.in);
    // read in user input
    String userString = IO.nextLine() + "-";

    int length = userString.length();

    int count = 0;
    String result = "";
    char new_char;

    for (int i = 0; i < length; i++) {
        new_char = userString.charAt(i);
        count++;
        if (new_char != userString.charAt(i + 1)) {
            if (count != 1) {
                result = result.concat(Integer.toString(count + 1));
            }
            result = result.concat(Character.toString(new_char));
            count = 0;
        }
        if (userString.charAt(i + 1) == '-')
            break;
    }

    System.out.println(result);
}

Comments

0

The problem is that your code checks if the previous letter, not the next, is the same as the current.

Your for loops basically goes through each letter in the string, and if it is the same as the previous letter, it figures out how many of that letter there is and puts that number into the result string. However, for a word like "hello", it will check 'e' and 'l' (and notice that they are preceded by 'h' and 'e', receptively) and think that there is no repeat. It will then get to the next 'l', and then see that it is the same as the previous letter. It will put '2' in the result, but too late, resulting in "hel2l" instead of "he2lo".

To clean up and fix your code, I recommend the following to replace your for loop:

   int count = 1;
   String result = "";
   for(int i=0;i<length;i++) {
       if(i < userString.length()-1 && userString.charAt(i) == userString.charAt(i+1))
           count++;
       else {
           if(count == 1)
               result += userString.charAt(i);
           else {
               result = result + count + userString.charAt(i);
               count = 1;
           }
       }
   }

Comment if you need me to explain some of the changes. Some are necessary, others optional.

Comments

0

Here is the solution for the problem with better time complexity:

public static void compressString (String string) {
  LinkedHashSet<String> charMap = new LinkedHashSet<String>();
  HashMap<String, Integer> countMap = new HashMap<String, Integer>();
  int count;
  String key;

  for (int i = 0; i < string.length(); i++) {
    key = new String(string.charAt(i) + "");
    charMap.add(key);
    if(countMap.containsKey(key)) {
     count = countMap.get(key);
     countMap.put(key, count + 1);
    }
    else {
     countMap.put(key, 1);
    }
  }

  Iterator<String> iterator = charMap.iterator();
  String resultStr = "";

  while (iterator.hasNext()) {
    key = iterator.next();
    count = countMap.get(key);

    if(count > 1) {
      resultStr = resultStr + count + key;
    }
    else{
      resultStr = resultStr + key;
    }
  }
  System.out.println(resultStr);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.