I have been given a task to create a class that given a String will create a palindrome with minimum number of assertions.
Example Runs:
Input: 123333
Output: 12333321
Input: 789
Output: 78987
Input: 1221
Output: 1221221
**Note a Palindrome should NOT return the same Palindrome.
I tried using a modified KMP algorithm as stated here.
I revert the string and compare it to the reverse + original string and then add the mismatches to the original string.
However my function only works for inputs with trailing digits (first example input) however an input like 1234 will return 1234123, '92837465' will return '928374659283746'
public static int[] computelps(String sample){
int[] lps = new int[sample.length()];
lps[0] = 0;
int i = 1;
int len = 0; // length of previous longest prefix suffix
while (i < sample.length()) {
if (sample.charAt(i) == sample.charAt(len)) {
len++;
lps[i] = len;
i++;
}
else
{
if (len != 0) {
len = lps[len - 1];
}
else {
lps[i] = 0;
i++;
}
}
}
return lps;
}
public static void Solution(File samplefile) throws Exception {
BufferedReader br = new BufferedReader(new FileReader(samplefile));
String firstline = br.readLine();
String line;
while ((line = br.readLine()) != null) {
String reverse_str = "";
String newline = line.replace(".", "");
for (int i = newline.length() - 1; i >= 0; i--) {
reverse_str += newline.charAt(i);
}
int [] lps = computelps(reverse_str); // computes the lps of the pattern string
String tot = reverse_str + newline;
// KMP Algorithm modified.
int x = 0; // index for total_string(tot)
int y = 0; // index for pattern
String palindrome = newline;
while (x < tot.length()){
if(reverse_str.charAt(y) == tot.charAt(x)){
y++;
x++;
}
if(y == reverse_str.length()) {
y = lps[y - 1];
}
else if( x < tot.length() && (reverse_str.charAt(y) != tot.charAt(x))){
palindrome += tot.charAt(x);
if ( y!= 0){
y = lps[y-1];
}
else{
x += 1;
}
}
}
System.out.println(palindrome);
}
}
I would appreciate any help. I find algorithms very challenging so please bear with me if my approach or code is sub-par.
*I fixed sample inputs and outputs as well as added my results.
It helps to split this problem in smaller problems, implement a separate method for each and check to see if each method works as expected. What will really help you will be to learn to use the debugger in your Ide. But until you do that you can test that each part of your code works as expected. So I simplified a little your code and split it up :
public static void main(String[] args){
System.out.println("computelps " + ("[0, 0, 0, 0]".equals(Arrays.toString(computelps("4321"))) ? "works" : "doesn't work" ));
System.out.println("reverse " + ("4321".equals(reverse("1234")) ? "works" : "doesn't work" ));
System.out.println("Solution " + ("1234321".equals(Solution("1234")) ? "works" : "doesn't work" ));
}
public static int[] computelps(String sample){
int[] lps = new int[sample.length()];
lps[0] = 0;
int i = 1;
int len = 0; // length of previous longest prefix suffix
while (i < sample.length()) {
if (sample.charAt(i) == sample.charAt(len)) {
len++;
lps[i] = len;
i++;
}
else
{
if (len != 0) {
len = lps[len - 1];
}
else {
lps[i] = 0;
i++;
}
}
}
return lps;
}
public static String Solution(String line) {
String newline = line.replace(".", "");
String reverse_str = reverse(newline);
int [] lps = computelps(reverse_str); // computes the lps of the pattern string
// KMP Algorithm modified.
return kpmModified(newline, reverse_str, lps);
}
private static String kpmModified(String newline, String reverse_str, int[] lps) {
int x = 0; // index for total_string(tot)
int y = 0; // index for pattern
String tot = reverse_str + newline;
String palindrome = newline;
while (x < tot.length()){
if(reverse_str.charAt(y) == tot.charAt(x)){
y++;
x++;
}
if(y == reverse_str.length()) {
y = lps[y - 1];
}
else if( x < tot.length() && (reverse_str.charAt(y) != tot.charAt(x))){
palindrome += tot.charAt(x);
if ( y!= 0){
y = lps[y-1];
}
else{
x += 1;
}
}
}
return palindrome;
}
private static String reverse(String newline) {
String reverse_str = "";
for (int i = newline.length() - 1; i >= 0; i--) {
reverse_str += newline.charAt(i);
}
return reverse_str;
}
And the result is
computelps works
reverse works
Solution doesn't work
So your bug is in kpmModified method. I can't spend more time and I'm not familiar with the algorithm but you should continue like this and figure our what part of that method has the bug.
I think you overthink the problem. The question is basically adding a string's reversed version back to it's original, but not every character, right? So you might need to find something like a pointer to tell the function where to start to reverse.
One example. Let the string be 12333. If we add every character from the index string.length() to 0, it will be 1233333321, which is not correct, since there are duplicated 3's. We need to ignore those, so we need to add characters from string.length() - numOfDuplicateAtEnd to 0.
public String palindromic(String num) {
int i = num.length() - 1;
while (i > -1 && num.charAt(i) == num.charAt(num.length() - 1))
i--;
for (int k = i; k > -1; --k)
num += num.substring(k, k + 1);
return num;
}
I am currently implementing Run Length Encoding for text compression and my algorithm does return Strings of the following form:
Let's say we have a string as input
"AAAAABBBBCCCCCCCC"
then my algorithm returns
"1A2A3A4A5A1B2B3B4B1C2C3C4C5C6C7C8C"
Now I want to apply Java String split to solve this, because I want to get the highest number corresponding to character. For our example it would be
"5A4B8C"
My function can be seen below
public String getStrfinal(){
String result = "";
int counter = 1;
StringBuilder sb = new StringBuilder();
sb.append("");
for (int i=0;i<str.length()-1;i++) {
char c = str.charAt(i);
if (str.charAt(i)==str.charAt(i+1)) {
counter++;
sb.append(counter);
sb.append(c);
}
else {
counter = 1;
continue;
}
}
result = sb.toString();
return result;
}
public static String getStrfinal(){
StringBuilder sb = new StringBuilder();
char last = 0;
int count = 0;
for(int i = 0; i < str.length(); i++) {
if(i > 0 && last != str.charAt(i)) {
sb.append(count + "" + last);
last = 0;
count = 1;
}
else {
count++;
}
last = str.charAt(i);
}
sb.append(count + "" + last);
return sb.toString();
}
Here is one possible solution. It starts with the raw string and simply iterates thru the string.
public static void main(String[] args) {
String input = "AAAABBBCCCCCCCDDDEAAFBBCD";
int index = 0;
StringBuilder sb = new StringBuilder();
while (index < input.length()) {
int count = 0;
char c = input.charAt(index);
for (; index < input.length(); index++) {
if (c != input.charAt(index)) {
count++;
}
else {
break;
}
}
sb.append(Integer.toString(count));
sb.append(c);
count = 0;
}
System.out.println(sb.toString());
}
But one problem with this method and others is what happens if there are digits in the text? For example. What if the string is AAABB999222AAA which would compress to 3A2B39323A. That could also mean AAABB followed by 39 3's and 23 A's
Instead of string Buffer you can use a map it will be much easier and clean to do so.
public static void main(String[] args) {
String input = "AAAAABBBBCCCCCCCCAAABBBDDCCCC";
int counter=1;
for(int i=1; i<input.length(); i++) {
if(input.charAt(i-1)==input.charAt(i)) {
counter=counter+1;
}else if(input.charAt(i-1)!=input.charAt(i)){
System.out.print(counter+Character.toString(input.charAt(i-1)));
counter=1;
}if(i==input.length()-1){
System.out.print(counter+Character.toString(input.charAt(i)));
}
}
}
This will gives
5A4B8C3A3B2D4C
UPDATES
I Agree with #WJS if the string contains number the out put becomes messy
hence if the System.out in above code will be exchange with below i.e.
System.out.print(Character.toString(input.charAt(i-1))+"="+counter+" ");
then for input like
AAAAABBBBCCCCCCCCAAABBBDD556677CCCCz
we get out put as below
A=5 B=4 C=8 A=3 B=3 D=2 5=2 6=2 7=2 C=4 z=1
This is one of the possible solutions to your question. We can use a LinkedHashMap data structure which is similar to HashMap but it also maintains the order. So, we can traverse the string and store the occurrence of each character as Key-value pair into the map and retrieve easily with its maximum occurrence.
public String getStrFinal(String str){
if(str==null || str.length()==0) return str;
LinkedHashMap<Character,Integer> map = new LinkedHashMap<>();
StringBuilder sb=new StringBuilder(); // to store the final string
for(char ch:str.toCharArray()){
map.put(ch,map.getOrDefault(ch,0)+1); // put the count for each character
}
for(Map.Entry<Character,Integer> entry:map.entrySet()){ // iterate the map again and append each character's occurence into stringbuilder
sb.append(entry.getValue());
sb.append(entry.getKey());
}
System.out.println("String = " + sb.toString()); // here you go, we got the final string
return sb.toString();
}
Method to compress a string using java and loops. For example, if dc = "aabbbccaaaaba, then c = "aab3cca4ba" Here is what I have so far. Please help/guide. Thanks.
int cnt = 1;
String ans = "";
for (int i = 0; i < dc.length(); i++) {
if ((i < dc.length()) && (dc.charAt(i) == dc.charAt(i++)) && (dc.charAt(i) == dc.charAt(i+=2))){
cnt++;
ans = ans + dc.charAt(i) + cnt;
}
else
ans = ans + dc.charAt(i);
setC(ans);
Unless you're restricted to using for loops, I believe this would do the trick:
String sb = "";
for (int i = 0; i < dc.length(); i++) {
char c = dc.charAt(i);
int count = 1;
while (i + 1 < dc.length() && (dc.charAt(i + 1)) == c) {
count++;
i++;
}
if (count > 1) {
sb += count;
}
sb += c;
}
System.out.println(sb);
edit:
Changed the example to use regular String instead of StringBuilder. However, I really advise against concatenating strings this way, especially if the string you're trying to compress is long.
It might be easier to get what you want by using Sting.toCharArray().
Then manipulate the array accordingly.
String dc = "aabbbccaaaaba";
String and = "";
int index = 0;
int cnt = 2;
While(dc.charAt(index) != null){
int index1 = index + 1;
char j = dc.charAt(index)
While(j.equals(dc.charAt(index1)){
cnt++;
}
//more code
index++;
}
It's a little incomplete but if you follow the logic I think it's what you're looking for. I won't do your assignment for you.
Easiest Solution: - Only one for loop, Time Complexity - O(n)
public static void main(String[] args) {
String str = "aabbbccaaaaba";
char[] arr = str.toCharArray();
int length = arr.length;
StringBuilder sb = new StringBuilder();
int count=1;
for(int i=0; i<length; i++){
if(i==length-1){
sb.append(arr[i]+""+count);
break;
}
if(arr[i]==arr[i+1]){
count++;
}
else{
sb.append(arr[i]+""+count);
count=1;
}
}
System.out.println(sb.toString());
}
Following is what I end up doing but i did not find right answer.
Example - If I have the sequence "hellloo" the output will be "lll". Please tell me what is wrong?
public class LongestSequenceOfChar {
static String testcase1="hellloo";
public static void main(String[] args) {
LongestSequenceOfChar test = new LongestSequenceOfChar();
String result = test.longestSequenceOfChar(testcase1);
System.out.println(result);
}
public String longestSequenceOfChar(String str){
String result="";
for(int i=0;i<str.length();i++){
char ch=str.charAt(i);
for(int j=i+1;j<str.length();j++){
char ch1=str.charAt(j);
if(ch!=ch1){
continue;
}
result+=ch;
}
}
return result;
}
}
You should have a counter that counts the number of the longest sequence for now. When you find a longer sequence, you should reset result and update the counter accordingly.
However, you can have better solutions:
Have an array of size 26 (the size of the English alphabet). Now you iterate on the String and for each char in it you add 1 in the corresponding cell in the helper array.
Use a HashMap that has the char as a key and the number it appears as the value. If it's a new char you simply put it with 0 value, if it exists, you increment the existing value.
Tip: Use a debugger, it can save your life.
1. Create a HashMap<Character,Integer>.. Integer-->count
2. Start from the beginning of your String.. For each character, check if it is already present in the hashmap
a. If Yes, just increment the count
b. if No, then add the character as key to the Map and set its count value to 1.
If there are three 'l' you only add two and in the next step are two 'l' and you add one of them. Then the same with the two 'o' where you are adding one. You only have to clear the result string when you step to the next letter and before save the result in another variable, but only if its is longer!
public String longestSequenceOfChar(String str){
String interimresult="";
String result=""; //final result
for(int i=0;i<str.length();i++){
char ch=str.charAt(i);
interimresult += ch; //add the letter once
for(int j=i+1;j<str.length();j++){
char ch1=str.charAt(j);
if(ch!=ch1){
break;
}
interimresult +=ch;
}
if(interimresult.length()>result.length())//store the result if it is longer
result = interimresult;
interimresult = ""; //clear to continue with the next letter
}
return result;
}
Here is a solution:
public String longestSequenceOfChar(String str) {
String result = "";
for (int i = 0; i < str.length(); i++) {
int j = i;
while(j < str.length() && str.charAt(j) == str.charAt(i)) {
j++;
}
// If this one is longer than previous, then asign it to result.
if(j - i > result.length()) {
result = str.substring(i, j);
}
}
return result;
}
This can be solved easily using HashMap. Checkout this sample code:
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
public class MaximumOccuringCharUsingHashMap {
public static void main(String[] args) {
String test = "test samples";
MaximumOccuringCharUsingHashMap mc =
new MaximumOccuringCharUsingHashMap();
System.out.println( mc.findMaximunOccurenceCharacter(test));
}
char findMaximunOccurenceCharacter(String input){
Map<Character, Integer> countHash =
new HashMap<Character, Integer>();
for(int i=0; i<input.length() ;i++ ){
char currentChar = input.charAt(i);
if(countHash.get(currentChar)==null){
countHash.put(currentChar, 1);
}else{
countHash.
put(currentChar, countHash.get(currentChar)+1);
}
}
int max = Collections.max(countHash.values());
char maxCharacter =0;
for(Entry<Character, Integer> entry :countHash.entrySet()){
if(entry.getValue() == max){
maxCharacter = entry.getKey();
}
}
return maxCharacter;
}
}
Above code will print s as output, which is occurring maximum number of times in the given String.
Try This...
public class HelloWorld {
public static void main(String[] args) {
System.out.println(maxLen(null));
System.out.println(maxLen(""));
System.out.println(maxLen("a"));
System.out.println(maxLen("aa"));
System.out.println(maxLen("abcddd"));
System.out.println(maxLen("abcd"));
System.out.println(maxLen("aabbba"));
}
public static String maxLen(String input) {
// Avoid NPEs
if (input == null) {
return null;
}
int maxLen = 0;
int tempLen = 0;
char prevChar = 0;
char c = 0;
char repeatChar = 0;
for (int i = 0; i < input.length(); i++) {
c = input.charAt(i);
if (c == prevChar) {
tempLen++;
if (tempLen > maxLen)
repeatChar = c;
} else {
maxLen = (tempLen > maxLen) ? tempLen : maxLen;
prevChar = c;
tempLen = 1;
}
}
maxLen = (tempLen > maxLen) ? tempLen : maxLen;
if (maxLen == 0 || maxLen == 1)
return "no sequence found";
else {
String str = "";
for (int i = 1; i <= maxLen; i++)
str += String.valueOf(repeatChar);
return str;
}
}
}
This will pass all test cases.
I need to create a method that receives a String and also returns a String.
Ex input: AAABBBBCC
Ex output: 3A4B2C
Well, this is quite embarrassing and I couldn't manage to do it on the interview that I had today ( I was applying for a Junior position ), now, trying at home I made something that works statically, I mean, not using a loop which is kind of useless but I don't know if I'm not getting enough hours of sleep or something but I can't figure it out how my for loop should look like. This is the code:
public static String Comprimir(String texto){
StringBuilder objString = new StringBuilder();
int count;
char match;
count = texto.substring(texto.indexOf(texto.charAt(1)), texto.lastIndexOf(texto.charAt(1))).length()+1;
match = texto.charAt(1);
objString.append(count);
objString.append(match);
return objString.toString();
}
Thanks for your help, I'm trying to improve my logic skills.
Loop through the string remembering what you last saw. Every time you see the same letter count. When you see a new letter put what you have counted onto the output and set the new letter as what you have last seen.
String input = "AAABBBBCC";
int count = 1;
char last = input.charAt(0);
StringBuilder output = new StringBuilder();
for(int i = 1; i < input.length(); i++){
if(input.charAt(i) == last){
count++;
}else{
if(count > 1){
output.append(""+count+last);
}else{
output.append(last);
}
count = 1;
last = input.charAt(i);
}
}
if(count > 1){
output.append(""+count+last);
}else{
output.append(last);
}
System.out.println(output.toString());
You can do that using the following steps:
Create a HashMap
For every character, Get the value from the hashmap
-If the value is null, enter 1
-else, replace the value with (value+1)
Iterate over the HashMap and keep concatenating (Value+Key)
use StringBuilder (you did that)
define two variables - previousChar and counter
loop from 0 to str.length() - 1
each time get str.charat(i) and compare it to what's stored in the previousChar variable
if the previous char is the same, increment a counter
if the previous char is not the same, and counter is 1, increment counter
if the previous char is not the same, and counter is >1, append counter + currentChar, reset counter
after the comparison, assign the current char previousChar
cover corner cases like "first char"
Something like that.
The easiest approach:- Time Complexity - O(n)
public static void main(String[] args) {
String str = "AAABBBBCC"; //input String
int length = str.length(); //length of a String
//Created an object of a StringBuilder class
StringBuilder sb = new StringBuilder();
int count=1; //counter for counting number of occurances
for(int i=0; i<length; i++){
//if i reaches at the end then append all and break the loop
if(i==length-1){
sb.append(str.charAt(i)+""+count);
break;
}
//if two successive chars are equal then increase the counter
if(str.charAt(i)==str.charAt(i+1)){
count++;
}
else{
//else append character with its count
sb.append(str.charAt(i)+""+count);
count=1; //reseting the counter to 1
}
}
//String representation of a StringBuilder object
System.out.println(sb.toString());
}
In the count=... line, lastIndexOf will not care about consecutive values, and will just give the last occurence.
For instance, in the string "ABBA", the substring would be the whole string.
Also, taking the length of the substring is equivalent to subtracting the two indexes.
I really think that you need a loop.
Here is an example :
public static String compress(String text) {
String result = "";
int index = 0;
while (index < text.length()) {
char c = text.charAt(index);
int count = count(text, index);
if (count == 1)
result += "" + c;
else
result += "" + count + c;
index += count;
}
return result;
}
public static int count(String text, int index) {
char c = text.charAt(index);
int i = 1;
while (index + i < text.length() && text.charAt(index + i) == c)
i++;
return i;
}
public static void main(String[] args) {
String test = "AAABBCCC";
System.out.println(compress(test));
}
Please try this one. This may help to print the count of characters which we pass on string format through console.
import java.util.*;
public class CountCharacterArray {
private static Scanner inp;
public static void main(String args[]) {
inp = new Scanner(System.in);
String str=inp.nextLine();
List<Character> arrlist = new ArrayList<Character>();
for(int i=0; i<str.length();i++){
arrlist.add(str.charAt(i));
}
for(int i=0; i<str.length();i++){
int freq = Collections.frequency(arrlist, str.charAt(i));
System.out.println("Frequency of "+ str.charAt(i)+ " is: "+freq);
}
}
}
Java's not my main language, hardly ever use it, but I wanted to give it a shot :]
Not even sure if your assignment requires a loop, but here's a regexp approach:
public static String compress_string(String inp) {
String compressed = "";
Pattern pattern = Pattern.compile("([\\w])\\1*");
Matcher matcher = pattern.matcher(inp);
while(matcher.find()) {
String group = matcher.group();
if (group.length() > 1) compressed += group.length() + "";
compressed += group.charAt(0);
}
return compressed;
}
This is just one more way of doing it.
public static String compressor(String raw) {
StringBuilder builder = new StringBuilder();
int counter = 0;
int length = raw.length();
int j = 0;
while (counter < length) {
j = 0;
while (counter + j < length && raw.charAt(counter + j) == raw.charAt(counter)) {
j++;
}
if (j > 1) {
builder.append(j);
}
builder.append(raw.charAt(counter));
counter += j;
}
return builder.toString();
}
The following can be used if you are looking for a basic solution. Iterate through the string with one element and after finding all the element occurrences, remove that character. So that it will not interfere in the next search.
public static void main(String[] args) {
String string = "aaabbbbbaccc";
int counter;
String result="";
int i=0;
while (i<string.length()){
counter=1;
for (int j=i+1;j<string.length();j++){
System.out.println("string length ="+string.length());
if (string.charAt(i) == string.charAt(j)){
counter++;
}
}
result = result+string.charAt(i)+counter;
string = string.replaceAll(String.valueOf(string.charAt(i)), "");
}
System.out.println("result is = "+result);
}
And the output will be :=
result is = a4b5c3
private String Comprimir(String input){
String output="";
Map<Character,Integer> map=new HashMap<Character,Integer>();
for(int i=0;i<input.length();i++){
Character character=input.charAt(i);
if(map.containsKey(character)){
map.put(character, map.get(character)+1);
}else
map.put(character, 1);
}
for (Entry<Character, Integer> entry : map.entrySet()) {
output+=entry.getValue()+""+entry.getKey().charValue();
}
return output;
}
One other simple way using Multiset of guava-
import java.util.Arrays;
import com.google.common.collect.HashMultiset;
import com.google.common.collect.Multiset;
import com.google.common.collect.Multiset.Entry;
public class WordSpit {
public static void main(String[] args) {
String output="";
Multiset<String> wordsMultiset = HashMultiset.create();
String[] words="AAABBBBCC".split("");
wordsMultiset.addAll(Arrays.asList(words));
for (Entry<String> string : wordsMultiset.entrySet()) {
if(!string.getElement().isEmpty())
output+=string.getCount()+""+string.getElement();
}
System.out.println(output);
}
}
consider the below Solution in which the String s1 identifies the unique characters that are available in a given String s (for loop 1), in the second for loop build a string s2 that contains unique character and no of times it is repeated by comparing string s1 with s.
public static void main(String[] args)
{
// TODO Auto-generated method stub
String s = "aaaabbccccdddeee";//given string
String s1 = ""; // string to identify how many unique letters are available in a string
String s2=""; //decompressed string will be appended to this string
int count=0;
for(int i=0;i<s.length();i++) {
if(s1.indexOf(s.charAt(i))<0) {
s1 = s1+s.charAt(i);
}
}
for(int i=0;i<s1.length();i++) {
for(int j=0;j<s.length();j++) {
if(s1.charAt(i)==s.charAt(j)) {
count++;
}
}
s2=s2+s1.charAt(i)+count;
count=0;
}
System.out.println(s2);
}
It may help you.
public class StringCompresser
{
public static void main(String[] args)
{
System.out.println(compress("AAABBBBCC"));
System.out.println(compress("AAABC"));
System.out.println(compress("A"));
System.out.println(compress("ABBDCC"));
System.out.println(compress("AZXYC"));
}
static String compress(String str)
{
StringBuilder stringBuilder = new StringBuilder();
char[] charArray = str.toCharArray();
int count = 1;
char lastChar = 0;
char nextChar = 0;
lastChar = charArray[0];
for (int i = 1; i < charArray.length; i++)
{
nextChar = charArray[i];
if (lastChar == nextChar)
{
count++;
}
else
{
stringBuilder.append(count).append(lastChar);
count = 1;
lastChar = nextChar;
}
}
stringBuilder.append(count).append(lastChar);
String compressed = stringBuilder.toString();
return compressed;
}
}
Output:
3A4B2C
3A1B1C
1A
1A2B1D2C
1A1Z1X1Y1C
The answers which used Map will not work for cases like aabbbccddabc as in that case the output should be a2b3c2d2a1b1c1.
In that case this implementation can be used :
private String compressString(String input) {
String output = "";
char[] arr = input.toCharArray();
Map<Character, Integer> myMap = new LinkedHashMap<>();
for (int i = 0; i < arr.length; i++) {
if (i > 0 && arr[i] != arr[i - 1]) {
output = output + arr[i - 1] + myMap.get(arr[i - 1]);
myMap.put(arr[i - 1], 0);
}
if (myMap.containsKey(arr[i])) {
myMap.put(arr[i], myMap.get(arr[i]) + 1);
} else {
myMap.put(arr[i], 1);
}
}
for (Character c : myMap.keySet()) {
if (myMap.get(c) != 0) {
output = output + c + myMap.get(c);
}
}
return output;
}
O(n) approach
No need for hashing. The idea is to find the first Non-matching character.
The count of each character would be the difference in the indices of both characters.
for a detailed answer: https://stackoverflow.com/a/55898810/7972621
The only catch is that we need to add a dummy letter so that the comparison for
the last character is possible.
private static String compress(String s){
StringBuilder result = new StringBuilder();
int j = 0;
s = s + '#';
for(int i=1; i < s.length(); i++){
if(s.charAt(i) != s.charAt(j)){
result.append(i-j);
result.append(s.charAt(j));
j = i;
}
}
return result.toString();
}
The code below will ask the user for user to input a specific character to count the occurrence .
import java.util.Scanner;
class CountingOccurences {
public static void main(String[] args) {
Scanner inp = new Scanner(System.in);
String str;
char ch;
int count=0;
System.out.println("Enter the string:");
str=inp.nextLine();
System.out.println("Enter th Char to see the occurence\n");
ch=inp.next().charAt(0);
for(int i=0;i<str.length();i++)
{
if(str.charAt(i)==ch)
{
count++;
}
}
System.out.println("The Character is Occuring");
System.out.println(count+"Times");
}
}
public static char[] compressionTester( char[] s){
if(s == null){
throw new IllegalArgumentException();
}
HashMap<Character, Integer> map = new HashMap<>();
for (int i = 0 ; i < s.length ; i++) {
if(!map.containsKey(s[i])){
map.put(s[i], 1);
}
else{
int value = map.get(s[i]);
value++;
map.put(s[i],value);
}
}
String newer="";
for( Character n : map.keySet()){
newer = newer + n + map.get(n);
}
char[] n = newer.toCharArray();
if(s.length > n.length){
return n;
}
else{
return s;
}
}
package com.tell.datetime;
import java.util.Stack;
public class StringCompression {
public static void main(String[] args) {
String input = "abbcccdddd";
System.out.println(compressString(input));
}
public static String compressString(String input) {
if (input == null || input.length() == 0)
return input;
String finalCompressedString = "";
String lastElement="";
char[] charArray = input.toCharArray();
Stack stack = new Stack();
int elementCount = 0;
for (int i = 0; i < charArray.length; i++) {
char currentElement = charArray[i];
if (i == 0) {
stack.push((currentElement+""));
continue;
} else {
if ((currentElement+"").equalsIgnoreCase((String)stack.peek())) {
stack.push(currentElement + "");
if(i==charArray.length-1)
{
while (!stack.isEmpty()) {
lastElement = (String)stack.pop();
elementCount++;
}
finalCompressedString += lastElement + "" + elementCount;
}else
continue;
}
else {
while (!stack.isEmpty()) {
lastElement = (String)stack.pop();
elementCount++;
}
finalCompressedString += lastElement + "" + elementCount;
elementCount=0;
stack.push(currentElement+"");
}
}
}
if (finalCompressedString.length() >= input.length())
return input;
else
return finalCompressedString;
}
}
public class StringCompression {
public static void main(String[] args){
String s = "aabcccccaaazdaaa";
char check = s.charAt(0);
int count = 0;
for(int i=0; i<s.length(); i++){
if(s.charAt(i) == check) {
count++;
if(i==s.length()-1){
System.out.print(s.charAt(i));
System.out.print(count);
}
} else {
System.out.print(s.charAt(i-1));
System.out.print(count);
check = s.charAt(i);
count = 1;
if(i==s.length()-1){
System.out.print(s.charAt(i));
System.out.print(count);
}
}
}
}
// O(N) loop through entire character array
// match current char with next one, if they matches count++
// if don't then just append current char and counter value and then reset counter.
// special case is the last characters, for that just check if count value is > 0, if it's then append the counter value and the last char
private String compress(String str) {
char[] c = str.toCharArray();
String newStr = "";
int count = 1;
for (int i = 0; i < c.length - 1; i++) {
int j = i + 1;
if (c[i] == c[j]) {
count++;
} else {
newStr = newStr + c[i] + count;
count = 1;
}
}
// this is for the last strings...
if (count > 0) {
newStr = newStr + c[c.length - 1] + count;
}
return newStr;
}
public class StringCompression {
public static void main(String... args){
String s="aabbcccaa";
//a2b2c3a2
for(int i=0;i<s.length()-1;i++){
int count=1;
while(i<s.length()-1 && s.charAt(i)==s.charAt(i+1)){
count++;
i++;
}
System.out.print(s.charAt(i));
System.out.print(count);
}
System.out.println(" ");
}
}
This is a leet code problem 443. Most of the answers here uses StringBuilder or a HashMap, the actual problem statement is to solve using the input char array and in place array modification.
public int compress(char[] chars) {
int startIndex = 0;
int lastArrayIndex = 0;
if (chars.length == 1) {
return 1;
}
if (chars.length == 0) {
return 0;
}
for (int j = startIndex + 1; j < chars.length; j++) {
if (chars[startIndex] != chars[j]) {
chars[lastArrayIndex] = chars[startIndex];
lastArrayIndex++;
if ((j - startIndex) > 1) {
for (char c : String.valueOf(j - startIndex).toCharArray()) {
chars[lastArrayIndex] = c;
lastArrayIndex++;
}
}
startIndex = j;
}
if (j == chars.length - 1) {
if (j - startIndex >= 1) {
j = chars.length;
chars[lastArrayIndex] = chars[startIndex];
lastArrayIndex++;
for (char c : String.valueOf(j - startIndex).toCharArray()) {
chars[lastArrayIndex] = c;
lastArrayIndex++;
}
} else {
chars[lastArrayIndex] = chars[startIndex];
lastArrayIndex++;
}
}
}
return lastArrayIndex;
}
}