Run-length encoding in java

376 Views Asked by At

How to print out the number of a specific digit along with the digit itself in form "nxw." n is the frequency of the number, w is the number itself.

So, for example, if the user's input was 1 1 1. The output would be 3x1.

If the user's input was 1 1 1 at the first line and 7 7 1 1 0 at the second line. The output would be 3x1.2x7.2x1.1x0. with no spaces.

Note:

  • loop ends with a dot.

  • numbers don't have to be in a specific order

  • user can input as many digits as they want.

So for example, Input can be 1 1 1 at the first line 7 7 1 1 0 at the second ... etc.

This is my code so far. But I know that it's not true.

import java.util.*;

public class LaufLaengenKodierung {

public static void main(String[] args) {
        
    Scanner sc = new Scanner(System.in);
        
    int freq = 0;
    int oldNum = 0;
    int num = 0;
    boolean first = true;
        
    while(sc.hasNextInt()) {
            
        int i = sc.nextInt();
            
        if(i == oldNum) {
                
            freq++;
            num = i;
                
        } else if(i != oldNum) {
                
            freq = 1;
            oldNum = i;
            num = i;
                
            if(first) {
                    
                first = false;
                num = i;
                freq = 1;
                    
            }
        }
    }
        
    System.out.print(freq + "x" + num + ".");
    sc.close();
}
        
}
2

There are 2 best solutions below

2
On BEST ANSWER

Existing code needs to be slightly refactored to print the frequency and integer value as soon as a sub-sequence of the same values ends.

static void printRLE(String input) {
    Scanner sc = new Scanner(input);
    int freq = 0;
    int oldNum = 0;
    boolean first = true;
        
    while(sc.hasNextInt()) {
            
        int i = sc.nextInt();
        
        if (i != oldNum || first) {
            if (first)
                first = false;
            else // integer value changed
                System.out.printf("%dx%d.", freq, oldNum);
            oldNum = i;
            freq = 1;
        } else {
            freq++;
        }
    }
    if (!first)    
        System.out.printf("%dx%d.%n", freq, oldNum);
    else 
        System.out.println("No integer found"); // or print 0x0 if it's correct
    sc.close();    
}

Tests:

String[] tests = {
    "",
    "abc.",
    "11 11 11",
    "1 1 1\n7 7 1 1 0",
    "0 0 0",
};    

for (String test: tests) {
    System.out.println("test=[" + test + "]");
    printRLE(test);
    System.out.println("--------");
}

Output:

test=[]
No integer found
--------
test=[abc.]
No integer found
--------
test=[11 11 11]
3x11.
--------
test=[1 1 1
7 7 1 1 0]
3x1.2x7.2x1.1x0.
--------
test=[0 0 0]
3x0.
--------

Update If separate digits need to be counted only (not the integer numbers), e.g. input 11 11 11 should be converted to 6x1. instead of 3x11. as shown above, the method should be refactored to process the digits inside numbers:

static void printRLEDigits(String input) {
    Scanner sc = new Scanner(input);
    int freq = 0;
    int oldNum = 0;
    boolean first = true;
        
    out: while(sc.hasNext()) {
            
        String s = sc.next(); // getting "number" delimited with whitespaces
        for (char c: s.toCharArray()) {
            if (!Character.isDigit(c)) {
                break out;
            }
            int i = c - '0';
            if (i != oldNum || first) {
                if (first)
                    first = false;
                else // digit changed
                    System.out.printf("%dx%d.", freq, oldNum);
                oldNum = i;
                freq = 1;
            } else {
                freq++;
            }
        }
    }
    if (!first)    
        System.out.printf("%dx%d.%n", freq, oldNum);
    else 
        System.out.println("No integer found");
    sc.close();    
}

Output for tests: "11 11 11", "112 223", "1 1 1\n7 7 1 1 0", "0 0 0":

test=[11 11 11]
6x1.
--------
test=[112 223]
2x1.3x2.1x3.
--------
test=[1 1 1
7 7 1 1 0]
3x1.2x7.2x1.1x0.
--------
test=[0 0 0]
3x0.
--------

Online demo of both methods printRLE and printRLEDigits

0
On

You have to save the count of each individual digit. You can do this by creating an int array of size 10, for the digits 0 to 9. Then it's a simple loop like

while(sc.hasNextInt()) {
        
    int i = sc.nextInt();
    
    countArray[i]++;
}

After that you check each element in the array and output the count of the digit, when it is bigger than 0. It can look like this:

for (int i=0; i<countArray.length; i++) {
    if (countArray[i] > 0) {
        System.out.printf("%dx%d.", countArray[i], i);
    }
}

Keep in mind that you have to check if the number entered by the user is in the limit of 0 to 9, otherwise you run into ArrayIndexOutOfBoundsExceptions.