How to decompress a string such as "a3b3" to aaabbb? [duplicate] - java

This question already has answers here:
Run-length decompression
(6 answers)
Closed 9 years ago.
I'm trying to take user input like a3b3 and decompress it to aaabbb. This is the code I came up with, and it prints a33b.
String getDecompressedText() {
int i;
int n = 1;
String d = "";
for (i = 0; i < compressedText.length(); i++){
if (Character.isDigit(compressedText.charAt(i)) == true) {
while (n < compressedText.charAt(i)-'0') {
d += compressedText.charAt(i);
n++;
}
}
else
d += compressedText.charAt(i);
}
return d;

here's your algorithm now:
for each character:
if it's not a digit, print it
if it is a digit, print the digit itself "digit - 1" times
not ideal. A few issues:
you printing the digit, not the letter preceding it. Use charAt(i-1)
you increment n, but never reset it back to 1. You should do that in the for loop.
you should indeed print the letter n - 1 times, since it got printed out once all by itself, so that's good
use a StringBuilder
the algorithm will break for things like a14 - 2-digit counts.

public static void main(String[] args) {
String compressedText = "a3b3";
int i;
int n = 1;
String d = "";
for (i = 0; i < compressedText.length(); i++) {
if (Character.isDigit(compressedText.charAt(i))) {
while (n < compressedText.charAt(i) - '0') {
d += compressedText.charAt(i - 1);
n++;
}
n = 0;
} else {
d += compressedText.charAt(i);
}
}
System.out.println(d);
}
Output:
aaabbbb
2 issues:
d += compressedText.charAt(i - 1); // Take the previous character, no the '3'
n = 0; // Reset the counter
Some notes:
Use a StringBuilder for concatenation in a loop
This will only work for single-digit numbers (0 - 9)

Related

How to print an integer with commas every 'd' digits, from right to left

I had to write a program that will receive an int 'n' and another one 'd' - and will print the number n with commas every d digits from right to left.
If 'n' or 'd' are negative - the program will print 'n' as is.
I although had to make sure that there is no commas before or after the number and I'm not allowed to use String or Arrays.
for example: n = 12345678
d=1: 1,2,3,4,5,6,7,8
d=3: 12,345,678
I've written the following code:
public static void printWithComma(int n, int d) {
if (n < 0 || d <= 0) {
System.out.println(n);
} else {
int reversedN = reverseNum(n), copyOfrereversedN = reversedN, counter = numberLength(n);
while (reversedN > 0) {
System.out.print(reversedN % 10);
reversedN /= 10;
counter--;
if (counter % d == 0 && reversedN != 0) {
System.out.print(",");
}
}
/*
* In a case which the received number will end with zeros, the reverse method
* will return the number without them. In that case the length of the reversed
* number and the length of the original number will be different - so this
* while loop will end the zero'z at the right place with the commas at the
* right place
*/
while (numberLength(copyOfrereversedN) != numberLength(n)) {
if (counter % d == 0) {
System.out.print(",");
}
System.out.print(0);
counter--;
copyOfrereversedN *= 10;
}
}
}
that uses a reversNum function:
// The method receives a number n and return his reversed number(if the number
// ends with zero's - the method will return the number without them)
public static int reverseNum(int n) {
if (n < 9) {
return n;
}
int reversedNum = 0;
while (n > 0) {
reversedNum += (n % 10);
reversedNum *= 10;
n /= 10;
}
return (reversedNum / 10);
}
and numberLength method:
// The method receives a number and return his length ( 0 is considered as "0"
// length)
public static int numberLength(int n) {
int counter = 0;
while (n > 0) {
n /= 10;
counter++;
}
return counter;
}
I've been told that the code doesn't work for every case, and i am unable to think about such case (the person who told me that won't tell me).
Thank you for reading!
You solved looping through the digits by reversing the number, so a simple division by ten can be done to receive all digits in order.
The comma position is calculated from the right.
public static void printWithComma(int n, int d) {
if (n < 0) {
System.out.print('-');
n = -n;
}
if (n == 0) {
System.out.print('0');
return;
}
int length = numberLength(n);
int reversed = reverseNum(n);
for (int i = 0; i < length; ++i) {
int nextDigit = reversed % 10;
System.out.print(nextDigit);
reversed /= 10;
int fromRight = length - 1 - i;
if (fromRight != 0 && fromRight % d == 0) {
System.out.print(',');
}
}
}
This is basically the same code as yours. However I store the results of the help functions into variables.
A zero is a special case, an exception of the rule that leading zeros are dropped.
Every dth digit (from right) needs to print comma, but not entirely at the right. And not in front. Realized by printing the digit first and then possibly the comma.
The problems I see with your code are the two while loops, twice printing the comma, maybe? And the println with a newline when <= 0.
Test your code, for instance as:
public static void main(String[] args) {
for (int n : new int[] {0, 1, 8, 9, 10, 234,
1_234, 12_345, 123_456, 123_456_789, 1_234_567_890}) {
System.out.printf("%d : ", n);
printWithComma(n, 3);
System.out.println();
}
}
Your code seems overly complicated.
If you've learned about recursion, you can do it like this:
public static void printWithComma(int n, int d) {
printInternal(n, d, 1);
System.out.println();
}
private static void printInternal(int n, int d, int i) {
if (n > 9) {
printInternal(n / 10, d, i + 1);
if (i % d == 0)
System.out.print(',');
}
System.out.print(n % 10);
}
Without recursion:
public static void printWithComma(int n, int d) {
int rev = 0, i = d - 1;
for (int num = n; num > 0 ; num /= 10, i++)
rev = rev * 10 + num % 10;
for (; i > d; rev /= 10, i--) {
System.out.print(rev % 10);
if (i % d == 0)
System.out.print(',');
}
System.out.println(rev);
}
Are you allowed to use the whole Java API?
What about something as simple as using DecimalFormat
double in = 12345678;
DecimalFormat df = new DecimalFormat( ",##" );
System.out.println(df.format(in));
12,34,56,78
Using...
,# = 1 per group
,## = 2 per group
,### = 3 per group
etc...
It took me a bunch of minutes. The following code snippet does the job well (explanation below):
public static void printWithComma(int n, int d) { // n=number, d=commaIndex
final int length = (int) (Math.log10(n) + 1); // number of digits;
for (int i = 1; i < Math.pow(10, length); i*=10) { // loop by digits
double current = Math.log10(i); // current loop
double remains = length - current - 1; // loops remaining
int digit = (int) ((n / Math.pow(10, remains)) % 10); // nth digit
System.out.print(digit); // print it
if (remains % d == 0 && remains > 0) { // add comma if qualified
System.out.print(",");
}
}
}
Using (Math.log10(n) + 1) I find a number of digits in the integer (8 for 12345678).
The for-loop assures the exponents of n series (1, 10, 100, 1000...) needed for further calculations. Using logarithm of base 10 I get the current index of the loop.
To get nth digit is a bit tricky and this formula is based on this answer. Then it is printed out.
Finally, it remains to find a qualified position for the comma (,). If modulo of the current loop index is equal zero, the dth index is reached and the comma can be printed out. Finally the condition remains > 0 assures there will be no comma left at the end of the printed result.
Output:
For 4: 1234,5678
For 3: 12,345,678
For 2: 12,34,56,78
For 1: 1,2,3,4,5,6,7,8

How do I sort a random integer into its digits least to greatest? [duplicate]

This question already has answers here:
How to sort Integer digits in ascending order without Strings or Arrays?
(13 answers)
Closed 3 years ago.
This an example input:
1002372
I need to get an output like this:
0012237
I am required to use loops, and boolean algebra.
I've converted the int into a String and I tried this for a start:
x = String.valueOf(a);
y = String.valueOf(b);
for(int z = 0; z < x.length(); z++)
{
if(x.charAt(z) == '0')
{
System.out.println(x.charAt(z));
}
if(x.charAt(z) == '1')
{
System.out.println(x.charAt(z));
}
}
Instead of running through and finding all the zeros first, the program just prints the numbers in order.
How do I check and print all of one integer at a time?
You are on the right path, to complete your logic, you'll need an additional loop to iterate digits 0 to 9 inclusive and compare the string at index z against it as follow.
Solution #1: Using string
String numberStr = String.valueOf(1002372);
for (int digit = '0'; digit <= '9'; digit++) {
for (int index = 0; index < numberStr.length(); index++) {
if (numberStr.charAt(index) == ((char) digit)) {
System.out.print(numberStr.charAt(index));
}
}
}
Solution #2: Using integer
int number = 1002372;
int tempNumber, tempDigit;
for (int digit = 0; digit <= 9; digit++) {
tempNumber = number;
while (tempNumber > 0) {
tempDigit = tempNumber % 10;
tempNumber = tempNumber / 10;
if (tempDigit == digit) {
System.out.print(tempDigit);
}
}
}
You can also use (if don't want to use loop),
public String sortNumber(int inputNumber)
{
// convert to string
String s_number = inputNumber + "";
// convert string to char array
char tempArray[] = s_number.toCharArray();
// sort tempArray
Arrays.sort(tempArray);
// return new sorted string
return new String(tempArray);
}

Error with multiplying char with a number and add with char ( Big Java Ex 6.2)

Currently going through an exercise in my book, but i'm stuck ( I havent learned arrays yet, this chapter is on loops nested loops and for loops)
The first part of the problem is to take a credit card number and then sum every other number backwards
Consider 4358 9795, which should output the sum 5+7+8 + 3 = 23.
Heres my solution which isn't working
class Checkit{
private String creditNum;
private int sum;
public Checkit(String creditNum)
{
this.creditNum = creditNum;
sum = 0;
}
public int getSum()
{
for (int i = creditNum.length() ; i > 0 ; i--)
{
char ch = creditNum.charAt(i-1);
if(i%2 == 1 )
{
sum+=ch;
}
}
return sum;
}
}
public class test{
public static void main(String [] args)
{
Checkit sampleNumber = new Checkit("4358 9795");
System.out.println(sampleNumber.getSum());
}
}
I'm not exactly sure whats wrong with my logic. ch is taking all of the values of my credit card number 5,7,8,3. But for some reason the sum is messing up.
BONUS PART
Take Each number that wasn't added and double it, so 9+9 + 5 + 4, double each of those terms ( that becomes 18 + 18 + 10 + 8), and then get the sum of 1 + 8 + 1 + 8 + 1 + 0 + 8.
I tried the bonus part, but for some reason every time I get 9, 9, 5,4 and times that char value by 2, I get letters. I don't think I can multiply chars by integers, so should I do conversions? Note I didn't learn arrays yet
NEW CODE
class Checkit {
private String creditCardNum;
private int sum;
public Checkit(String creditCardNum) {
sum = 0;
this.creditCardNum = creditCardNum;
}
public int getSum() {
creditCardNum = creditCardNum.replaceAll("\\s+", "");
for (int i = creditCardNum.length(); i > 0; i--) {
char ch = creditCardNum.charAt(i - 1);
if (i % 2 == 0) {
sum += Character.getNumericValue(ch);
}
}
return sum;
}
public int doubleDigitSum() {
sum = 0;
creditCardNum = creditCardNum.replaceAll("\\s", "");
for (int i = creditCardNum.length(); i > 0; i--) {
char ch = creditCardNum.charAt(i - 1);
if (i % 2 == 1) {
int newChar = Character.getNumericValue(ch) * 2;
String newCharString = Integer.toString(newChar);
for (int j = 0; j < newCharString.length(); j++) {
char sumThis = newCharString.charAt(j);
sum += Character.getNumericValue(sumThis);
}
}
}
return sum;
}
}
public class DataSet{
public static void main(String [] args) {
Checkit data = new Checkit("4358 9795");
System.out.println(data.getSum());
System.out.println(data.doubleDigitSum());
}
}
You're adding char values rather than int values. Replace sum+=ch; with
sum += ch - '0';
The reason why this works as opposed to the original solution is that when you're adding char values to an int value, the char is converted to a decimal via its ASCII value. For example, '5' has a ASCII dec value of 53. However, '5' - '0' equals 5. More on these ASCII values can be found here, http://www.asciitable.com/
Your issue is that you are not converting the char to an integer:
public int getSum()
{
for (int i = creditNum.length() ; i > 0 ; i--)
{
char ch = creditNum.charAt(i-1);
if(i%2 == 1 )
{
sum+=ch;
}
}
return sum;
}
Fun fact that's causing your error - chars are numbers! They're simply a number that represents the ascii character code of the letter. So when you add them to a sum, Java is OK with that and just adds the corresponding number for the char '8' for example, which is 56.
To make your code work, you need to properly convert to an integer:
public int getSum()
{
for (int i = creditNum.length() ; i > 0 ; i--)
{
char ch = creditNum.charAt(i-1);
if(i%2 == 1)
{
sum+=Character.getNumericValue(ch);
}
}
return sum;
}
for (int i = creditNum.length() ; i > 0 ; i--) {
char ch = creditNum.charAt(i-1);
First iteration thru loop gets IndexOutOfBounds exception. And then you never check the initial character of the credit card number, since your termination criterion is ( i > 0 ), not (i >= 0)
And why not just use i -= 2 for the increment instead of the if-check?

how can i add values from a loop in java

I've recently been given question for uni that is in regards to a credit card statement which says i have a string of numbers, then i convert these numbers to separate integers then i increment them by the power of 10 depending on their position in the string using horners method
i then have to add the values i get from the loop to make 1 whole integer.
I Know this is an odd way to convert a string to an int but my assignment states that i have to use horners method to convert the string rather than use the inbuilt java classes/methods
My question is, How can i add the separate weighted numbers and concatenate them into one single number.
If it helps an example would be,
Given a card number 1234, the number is weighted according to its position and length so:
1 - 1000
2 - 200
3 - 30
4 - 4
Then these are added to create a whole number
1, 2, 3,4 ---> 1234
Here is my code thus far
public static long toInt(String digitString) {
long answer = 0;
long val = 0;
String s = "";
for (int j = 0; j < digitString.length(); j++) {
val = digitString.charAt(j) - '0';
val = (long) (val * Math.pow(10, (digitString.length() - 1) - j));
System.out.println(val);
}
return answer;
}
Most probably I am not following you, because this sounds too simple.
But to return a long (or integer) all you have to do is to sum these numbers:
public static long toLong(String digitString) {
long answer = 0;
long val = 0;
for (int j = 0; j < digitString.length(); j++) {
val = digitString.charAt(j) - '0';
val = (long) (val * Math.pow(10, (digitString.length() - 1) - j));
answer += val; // here! :)
//System.out.println(val);
}
return answer;
}
Please note that this is not going to work with negative numbers, so here is a more complex version:
public static long toLong(String digitString) {
long answer = 0;
long val = 0;
boolean negative = false;
int j = 0;
if (digitString.charAt(0) == '-') {
negative = true;
j = 1;
} else if (digitString.charAt(0) == '+')
j = 1;
for (; j < digitString.length(); j++) {
if (!Character.isDigit(digitString.charAt(j)))
throw new NumberFormatException(digitString);
val = digitString.charAt(j) - '0';
val = (long) (val * Math.pow(10, (digitString.length() - 1) - j));
answer += val;
}
return negative ? -answer : answer;
}
This code will work with negative numbers and with weird numbers that start with a + sign as well. If there is any other character, it will throw an exception.
I think your code is not Object-Oriented and really hard to read and understand.
Basic, the problem is a mapping and really simple.
If you are writing code in Java, better to use in OO way, though I don't like java very much.
Checkout my code
#Test
public void testCardScoreSystem() {
Map<String, String> scoreMapping = new HashMap<String, String>();
scoreMapping.put("1", "1000");
scoreMapping.put("2", "200");
scoreMapping.put("3", "30");
scoreMapping.put("4", "4");
String[] input = {"1", "2", "3", "4"};
long score = 0;
for (String str : input) {
String mappedValue = scoreMapping.get(str);
if (mappedValue == null) {
throw new RuntimeException("Hey dude, there is no such score mapping system! " + str);
}
score += Long.valueOf(mappedValue);
}
System.out.println(score);
}

algorithm to create a char array from permutations list in java

I'm sorry for the slightly confusing title, I'm unsure of how to phrase it.
I need to create a char array allowing for every possible permutation of a character set.
If I were to give you:
char[] charSet = {"a", "b", "c"};
BigInteger value = n; //where n is a number >= 0
char[] charArray = createCharArray(value, charSet);
How can I create charArray from value and charSet such that if I ran:
createCharArray(new BigInteger("6"), {"a", "b", "c"});
it would return {"a", "c"}
because
a=1
b=2
c=3
aa=4
ab=5
ac=6
Here's what I have so far:
private char[] createCharArray(BigInteger value, char[] charSet){
List<Character> charArray = new ArrayList<Character>();
if (value.compareTo(this.max) == 0)
System.out.println("");
BigInteger csSize = new BigInteger(String.valueOf(charSet.length));
if(this.powers.isEmpty())
this.powers.add(0, csSize.pow(0));
if(this.sumPowers.isEmpty())
this.sumPowers.add(0, csSize.pow(0));
BigInteger curPow;
int i = 1;
while((curPow = csSize.pow(i)).compareTo(value) <= -1){
if(this.powers.size() <= i)
this.powers.add(i, curPow);
if(this.sumPowers.size() <= i)
this.sumPowers.add(i, this.sumPowers.get(i-1).add(curPow));
i += 1;
}
i -= 1;
while (i >= 0 && value.compareTo(BigInteger.ZERO) >= 0){
if (i <= 1){
int charNum = value.divide(this.sumPowers.get(0)).intValue() - 1;
charArray.add(charSet[charNum]);
}
else{
int charNum = value.divide(this.sumPowers.get(i-1).subtract(BigInteger.ONE)).intValue() - 1;
charArray.add(charSet[charNum]);
}
value = value.subtract(this.powers.get(i));
i -= 1;
}
char[] returnArray = new char[charArray.size()];
int j = 0;
while(j<charArray.size()){
returnArray[j] = charArray.get(j);
j += 1;
}
return returnArray;
}
It certainly could use some help, as a value of 0 fails, values of 1 and 2 succeed, 3-8 fail, 9, 10 succeed, etc.
EDIT: To be clear, the value parameter must be able to be ANY number n > 0. This is why I've chosen BigInteger
Make a class that has two fields:
private char letter;
private int value;
public <classname>(char letter){
this.letter = letter;
value = 0;
}
//Setters and getters
Then in your main when initializing an array (via for loop) set the value to i + 1 (getting rid of 0)
for(int i = 0; i < <yourarray>.length; i ++){
//Assuming you initialized your objects before
<yourarray>[i].<setterforvalue>(i + 1);
}
And then to calculate them together:
for(int i = 0; i < <yourarray>.length; i ++){
for(int j = 0; j < <yourarray>.length; j ++){
if(<yourarray>[i] + <yourarray>[j] == <needednumber>){
//Do what you need to do with the value
}
}
}
Okay after much thinking and eventually breaking it down to using numbers 0-9 instead of characters. Here's the breakdown: Think about how regular base 10 numerals are created.
The number 194 is made up of a 4 in the ones column, a 9 in the tens, and a 1 in the hundreds. The difference between ones, tens, and hundreds is multiplication/division by 10, which is the base.
So I figured that I could mod the 194 by the base (10) to get 4, the ones. then divide by 10 to remove the ones column. mod again to get 9, then divide by 10, mod again to get 1, divide by 10. once the division creates a number that is exactly 0, we are done. This is because we cannot make a number 000194.
For my function, My base is the length of the character set, and the value is like 194 in the example above.
private static void createCharArray(BigInteger value, char[] charSet){
List<Character> charArray = new ArrayList<Character>();
BigInteger csSize = BigInteger.valueOf(charSet.length);
if (value.compareTo(BigInteger.ZERO) == 0)
charArray.add(0, charSet [0]);
else{
BigInteger modded = value.mod(csSize);
BigInteger digit = value.divide(csSize);
while (modded.compareTo(BigInteger.ZERO) != 0 || digit.compareTo(BigInteger.ZERO) != 0){
if(modded.compareTo(BigInteger.ZERO) == 0){
charArray.add(0, charSet[csSize.subtract(BigInteger.ONE).intValue()]);
value = value.subtract(BigInteger.ONE);
}
else
charArray.add(0, charSet[modded.subtract(BigInteger.ONE).intValue()]);
value = value.divide(csSize);
modded = value.mod(csSize);
digit = value.divide(csSize);
}
}
for(char c : charArray)
System.out.print(c);
System.out.println();
}
public static void main(String[] args) {
long start = System.nanoTime();
String characters = "";
characters += "0123456789";
characters += "abcdefghijklmnopqrstuvwxyz";
characters += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
characters += " !\"#$%&'()*+,-./:;<=>?#[\\]^_`{|}~";
char[] cs = characters.toCharArray();
Arrays.sort(cs);
createCharArray(new BigInteger("1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"), cs);
long total = System.nanoTime() - start;
System.out.println("Completed in: " + total + " billionths of a second");
System.out.println("Completed in: " + total/1000000 + " thousandth(s) of a second");
}
If you run this, note that that BigInteger 4 lines from the bottom is 100 characters long. On my machine, it takes only 1/1000 th of a second (1 Millisecond).

Categories