user2880877
user2880877

Reputation:

Compression algorithm in java

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);
}

}

Upvotes: 0

Views: 10435

Answers (7)

I. Ahmed
I. Ahmed

Reputation: 2534

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);
}

Upvotes: 0

Vikasdeep Singh
Vikasdeep Singh

Reputation: 21766

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);
}

Upvotes: 1

asaini007
asaini007

Reputation: 836

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.

Upvotes: 0

Matt Penna
Matt Penna

Reputation: 117

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

Upvotes: 0

Christian Tapia
Christian Tapia

Reputation: 34146

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);
}

Upvotes: 0

Charles Forsythe
Charles Forsythe

Reputation: 1861

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();
}

Upvotes: 0

Peter Lawrey
Peter Lawrey

Reputation: 533510

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.

Upvotes: 1

Related Questions