Java string compression is printing wrong string. What am I missing here? - java

I have a string "aaabbaaaavvvd", it should be compressed to a3b2a4v3d
But when I run my code it prints out b3a2v4d3
Strangely, it starts with b instead of a
public class compression {
public String compress(String str){
char chararr[] = str.toCharArray();
StringBuilder sb = new StringBuilder();
int count=1;
char previous = chararr[0];
for(int i=1; i<chararr.length; i++) {
char current = chararr[i];
if(current == previous){
count++;
} else {
sb.append(current).append(count);
count = 1;
}
previous = current;
}
System.out.println(sb.toString());
return sb.toString();
}
public static void main(String args[]){
compression test = new compression();
String str = "aaabbaaaavvvd";
test.compress(str);
}
}

Error on line:
sb.append(current).append(count);
Think about the if statement
if(current == previous){
count++;
} else {
sb.append(current).append(count);
count = 1;
}
As your code steps through each character, the if statement is only false if the current character is not equal to the last (i.e. the current character is the start of a new sequence of characters).
Stepping through one-by-one:
Index 1: previous == 'a', current == 'a', if-statement: true - increments
Index 2: previous == 'a', current == 'a', if-statement: true - increments
Index 3: previous == 'a', current == 'b', if-statement: false - prints and reset
Note how upon the third index, current is b rather than the required character a, outputting b3 as opposed to a3.
Replace the append chain with previous to fix:
if(current == previous){
count++;
} else {
sb.append(previous).append(count);
count = 1;
}

You have 3 issues:
When current == previous you should add 1 to counter and then continue
When you exit the loop - print the last char that you process
You should append the previous char - not the current sb.append(previous)
your code should look like this:
public String compress(String str){
char chararr[] = str.toCharArray();
StringBuilder sb = new StringBuilder();
int count=1;
char previous = chararr[0];
for(int i=1; i<chararr.length; i++) {
char current = chararr[i];
if(current == previous){
count++;
continue;
} else {
sb.append(previous).append(count);
count = 1;
}
previous = current;
}
sb.append(previous).append(count);
System.out.println(sb.toString());
return sb.toString();
}

This code sample works. I have changed sb.append(current) to sb.append(previous) and added a sb.append(previous).append(count) outside the for loop to account for the last character
public class compression {
public String compress(String str){
char chararr[] = str.toCharArray();
StringBuilder sb = new StringBuilder();
int count=1;
char previous = chararr[0];
for(int i=1; i<chararr.length; i++) {
char current = chararr[i];
if(current == previous){
count++;
} else {
sb.append(previous).append(count);
count = 1;
}
previous = current;
}
sb.append(previous).append(count);
System.out.println(sb.toString());
return sb.toString();
}
public static void main(String args[]){
compression test = new compression ();
String str = "aaabbaaaavvvd";
test.compress(str);
}
}

Try this:
public class Compression {
public String compress(String str) {
char chararr[] = str.toCharArray();
StringBuilder sb = new StringBuilder();
int count = 0;
char previous = chararr[0];
for (int i = 0; i < chararr.length; i++) {
char current = chararr[i];
if (current == previous) {
count++;
} else {
sb.append(previous);
if (count != 1) {
sb.append(count);
}
count = 1;
}
previous = current;
}
sb.append(previous);
if (count != 1) {
sb.append(count);
}
return sb.toString();
}
public static void main(String args[]) {
Compression test = new Compression();
System.out.println(test.compress("aaabbaaaavvvd"));
System.out.println(test.compress("aaabbaaaavvvdddd"));
}
}
Output:
a3b2a4v3d
a3b2a4v3d4

Try something like below:
public String compress(String str){
String result="";
StringBuilder sb = new StringBuilder(str);
while(sb.length() != 0){
int count = 0;
char test = sb.charAt(0);
while(sb.indexOf(test+"") != -1){
sb.deleteCharAt(sb.indexOf(test+""));
count++;
}
result=result+test+count;
}
System.out.println(result);
return sb.toString();
}

Related

Finding first non repeating character in a string in relation to Big O

I solved a task concerning finding the first non-repeating character. For example, given the input "apple" the answer would be "a", the first character that isn't repeated. Even though "e" is not repeated it's not the first character. Another example: "lalas" answer is "s".
public static char firstNonRepeatingCharacter(String input) {
boolean unique;
int count = input.length();
char[] chars = input.toCharArray();
for (int i = 0; i < input.length(); i++) {
unique = true;
for (int j = 0; j < input.length(); j++) {
count--;
char c = chars[i];
if (i != j && c == chars[j]) {
unique = false;
break;
}
}
if (unique) {
return input.charAt(i);
}
}
return (0);
}
I want to simplify this code due to the nested loop having O(n2) complexity. I have been looking at the code trying to figure out if i could make it any faster but nothing comes to mind.
Another way is to find the first and last indexOf the character. If both are same then it is unique.
public static char firstNonRepeatingCharacter(String input) {
for(char c:input.toCharArray())
if(input.indexOf(c) == input.lastIndexOf(c))
return c;
return (0);
}
EDIT:
Or with Java 8+
return (char) input.chars()
.filter(c -> input.indexOf(c) == input.lastIndexOf(c))
.findFirst().orElse(0);
O(n) is better.
Use an intermedian structure to handle the number of repetitions.
public static char firstNonRepeatingCharacter(String input) {
boolean unique;
int count = input.length();
char[] chars = input.toCharArray();
for (int i = 0; i < input.length(); i++) {
unique = true;
for (int j = 0; j < input.length(); j++) {
count--;
char c = chars[i];
if (i != j && c == chars[j]) {
unique = false;
break;
}
}
if (unique) {
return input.charAt(i);
}
}
return (0);
}
public static char firstNonRepeatingCharacterMyVersion(String input) {
Map<String,Integer> map = new HashMap();
// first iteration put in a map the number of times a char appears. Linear O(n)=n
for (char c : input.toCharArray()) {
String character = String.valueOf(c);
if(map.containsKey(character)){
map.put(character,map.get(character) + 1);
} else {
map.put(character,1);
}
}
// Second iteration look for first element with one element.
for (char c : input.toCharArray()) {
String character = String.valueOf(c);
if(map.get(character) == 1){
return c;
}
}
return (0);
}
public static void main(String... args){
System.out.println(firstNonRepeatingCharacter("potatoaonionp"));
System.out.println(firstNonRepeatingCharacterMyVersion("potatoaonionp"));
}
See this solution. Similar to the above #Lucbel. Basically, using a LinkedList. We store all non repeating. However, we will use more space. But running time is O(n).
import java.util.LinkedList;
import java.util.List;
public class FirstNone {
public static void main(String[] args) {
System.out.println(firstNonRepeatingCharacter("apple"));
System.out.println(firstNonRepeatingCharacter("potatoaonionp"));
System.out.println(firstNonRepeatingCharacter("tksilicon"));
}
public static char firstNonRepeatingCharacter(String input) {
List<Character> charsInput = new LinkedList<>();
char[] chars = input.toCharArray();
for (int i = 0; i < input.length(); i++) {
if (charsInput.size() == 0) {
charsInput.add(chars[i]);
} else {
if (!charsInput.contains(chars[i])) {
charsInput.add(chars[i]);
} else if (charsInput.contains(chars[i])) {
charsInput.remove(Character.valueOf(chars[i]));
}
}
}
if (charsInput.size() > 0) {
return charsInput.get(0);
}
return (0);
}
}
private static int Solution(String s) {
// to check is values has been considered once
Set<String> set=new HashSet<String>();
// main loop
for (int i = 0; i < s.length(); i++) {
String temp = String.valueOf(s.charAt(i));
//rest of the values
String sub=s.substring(i+1);
if (set.add(temp) && !sub.contains(temp)) {
return i;
}
}
return -1;
}

Is the logic in my program close in terms of arriving to the solution?

I'm trying to count the number of times a letter appears in a string (aabcccccaaa) and placing the number of times that it does into a new string along with the corresponding letter. The problem's that I get a StringIndexOutOfBoundsException.
I kind of have a clue why but I think it's mainly because my logic is flawed with this problem.
Am I on the right track? What am I doing wrong and how can I fix it?
For example, the output should be a2b1c5a3
Here's my code:
public class Problem {
public static void main(String []args) {
String str = "aabcccccaaa";
System.out.println(compressBad(str));
}
public static String compressBad(String str) {
int countConsecutive = 0;
String compressedString = "";
for(int i = 0; i < str.length(); i++) {
if(str.charAt(i) != str.charAt(i + 1)) {
countConsecutive++;
compressedString += "" + str.charAt(i) + countConsecutive;
countConsecutive = 0;
}
}
return compressedString;
}
}
This line str.charAt(i + 1) will read out of bounds when i is the last index, i+1 is now out of bounds.
For what it's worth, here's what I would do :
public static String compressBad(final String str) {
if (str == null || str.length() < 0) {
return "";
}
int countConsecutive = 0;
StringBuilder sb = new StringBuilder();
char previousLetter = str.charAt(0);
for (char c : str.toCharArray()) {
if (c == previousLetter) {
countConsecutive++;
} else {
sb.append(previousLetter).append(countConsecutive);
previousLetter = c;
countConsecutive = 1;
}
}
sb.append(previousLetter).append(countConsecutive);
return sb.toString();
}

What is wrong with this Vowel question? Out of index

I'm doing a homework task that is:
Find a unique vowel in the string that is preceded by a consonant, and this consonant is preceded by a vowel.
Example: "eeaaAOEacafu"
Result is: u
What i already did:
Main.class
public class Principal {
public static void main(String[] args) {
// TODO Auto-generated method stub
Stream str = new Stream();
str.setText("eeaaAOEacafu");
System.out.println(str.returnChar(str.getVowel()));
}
Stream.class
public class Stream {
String text;
char vowel;
public String getText() {
return texto;
}
public void setText(String text) {
this.text = text;
}
public char getVowel() {
return vowel;
}
public void setVowel(char vowel) {
this.vowel = vowel;
}
public boolean isVowel(String str) {
str = str.toLowerCase();
for(int i=0; i<str.length(); i++) {
char c = str.charAt(i);
if(c=='a' || c=='e' || c=='i' || c=='o'|| c=='u') {
return true;
} else {
return false;
}
}
return false;
}
public char returnChar(String str) {
char last;
char next;
char result = '0';
int j=1;
for(int i=0; i<str.length(); i++) {
last = str.charAt(i-1);
next = str.charAt(i+1);
j++;
if(!vogal(str.charAt(i))) {
if(vogal(last) && vogal(next)) {
result = next;
}
}
}
this.setVowel(result);
return result;
} }
This returns: String index out of range: -1
This j=1, was to fix this -1 out of range. It fix but i got new one: out of range 11 because of the next.
The thing is: I have to use pure java and no API.
Can you guys help me?
use regular expressions for the test and locating the character
[aeiouAEIOU][bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ]([aeiouAEIOU])
Use a String as a cheap map to keep track of which vowels you've already seen. Also, keep a count of how many consecutive consonants you've encountered. Then, when you hit a vowel that you haven't seen before preceded by a single consonant you've found your answer.
public static void main(String[] args)
{
String s = "eeaaAOEacafu".toLowerCase();
int consCount = 0;
String seenVowels = "";
for(int i=0; i<s.length(); i++)
{
char c = s.charAt(i);
if("aeiou".indexOf(c) >= 0)
{
if(seenVowels.indexOf(c) == -1)
{
if(consCount == 1)
{
System.out.println("Result: " + c);
break;
}
seenVowels += c;
}
consCount = 0;
}
else consCount++;
}
}
Output:
Result: u
The above works if we take 'unique' to mean that we haven't seen the vowel before. If the vowel has to be unique within the input string then things are a little more complicated. Now we have to keep track of each vowel that meets the original criteria, but remove the solution if we subsequently encounter another instance of the same vowel.
Here's some code to illustrate:
public static void main(String[] args)
{
String s = "afuxekozue".toLowerCase();
int consCount = 0;
String seenVowels = "";
String answer = "";
for(int i=0; i<s.length(); i++)
{
char c = s.charAt(i);
if("aeiou".indexOf(c) >= 0)
{
if(seenVowels.indexOf(c) == -1)
{
if(consCount == 1)
{
answer += c;
}
seenVowels += c;
}
else if(answer.indexOf(c) >= 0)
{
answer = answer.replaceAll(String.valueOf(c), "");;
}
consCount = 0;
}
else consCount++;
}
if(answer.length() > 0)
System.out.println("Result: " + answer.charAt(0));
}
Output:
Result: o

Capitalizing the first letter in a string. What am I doing wrong?

What am I doing wrong? When I run my program it only prints some of my string, and it does not capitalize the first letter..
public class StringTraining extends ConsoleProgram {
public void run() {
String str = "halOOlOO";
capitalize(str);
}
private String capitalize(String str){
String s = "";
char ch;
for(int i = 0;i<str.length();i++) {
ch = str.charAt(i);
if(i==0 && Character.isLowerCase(ch)) {
Character.toUpperCase(ch);
s += ch;
i++;
} else {
Character.toLowerCase(ch);
s += ch;
i++;
}
}
println(s);
return s;
}
}
You should not increment i again in the loop since it will be done automatically in the signature of the loop.
You have to assign Character.toUpperCase(ch) to the String or append it.
I'd suggest you use a StringBuilder when looping to build a String object
Correction
private static String capitalize(String str){
StringBuilder s = new StringBuilder();
char ch;
for(int i = 0;i<str.length();i++) {
ch = str.charAt(i);
if(i==0 && Character.isLowerCase(ch)) {
s.append(Character.toUpperCase(ch));
} else {
s.append(Character.toLowerCase(ch));
}
}
return s.toString();
}
Output
Halooloo
You need to assign the variable ch to the upper or lower case value:
for(int i = 0;i<str.length();i++) {
ch = str.charAt(i);
if(i==0 && Character.isLowerCase(ch)) {
ch = Character.toUpperCase(ch);
s += ch;
} else {
ch = Character.toLowerCase(ch);
s += ch;
}
}
Remove some unnecessary codes from your capitalize(String) method such as i++ and use
s += String.valueOf(Character.toUpperCase(ch)); code instead of
Character.toUpperCase(ch);
s += ch;
Complete capitalize(String) method
private static String capitalize(String str) {
String s = "";
char ch;
for (int i = 0; i < str.length(); i++) {
ch = str.charAt(i);
if (i == 0 && Character.isLowerCase(ch)) {
s += String.valueOf(Character.toUpperCase(ch));
} else {
s += String.valueOf(Character.toLowerCase(ch));
}
}
println(s);
return s;
}
toLowerCase() return a string, you need to assign it to ch.
You also need to increment your i only one time (in the for, and not in the if)
Change your capitalize(String str) method like this -
private static String capitalize(String str) {
char[] chars = str.toCharArray();
String caps = chars[0]+"";
caps = caps.toUpperCase();
String output = caps;
for(int i=1;i<chars.length;i++) {
output = output + chars[i];
}
return output;
}
Output :
HalOOlOO

remove duplicate characters from a string

import java.util.Scanner;
public class StringWithoutDuplicate {
public static void stringWithoutDuplicate(String s1)
{
int n = s1.length();
int i = 0;
while(i<n)
{
if(s1.charAt(i) == s1.charAt(i+1))
{
if(s1.charAt(i) == s1.charAt(n-1))
{
System.out.println(s1.charAt(i));
}
i++;
}
else if(s1.charAt(i) != s1.charAt(i+1))
{
if(s1.charAt(i) == s1.charAt(n-1))
{
System.out.println(s1.charAt(i));
}
System.out.println(s1.charAt(i));;
i++;
}
}
}
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
s.useDelimiter(",");
String s1 = s.next();
System.out.println(s1);
stringWithoutDuplicate(s1);
}
}
The code is giving the output but with an exception
please tell me the error in my code and ways to correct it.
I don't want to change the logic of my code so kindly solve it using this logic only.
ERROR:
Range of your i is from 0 to (n-1) which is same as the range of index of characters in your string s1. This is correct.
But during the last iteration of your while loop, i = n-1
At this point, s1.charAt(i+1) becomes same as s1.charAt(n). This should be giving an error.
public static void stringWithoutDuplicate(String s1) {
int prev = -1;
for (int i = 0, size = s1.length(); i < size; ++i) {
char c = s1.charAt(i);
if (c != prev) {
System.out.println(c);
prev = c;
}
}
}

Categories

Resources