I have somehow got the output with the help of some browsing. But I couldn't understand the logic behind the code. Is there any simple way to achieve this?
public class LetterCount {
public static void main(String[] args)
{
String str = "aabbcccddd";
int[] counts = new int[(int) Character.MAX_VALUE];
// If you are certain you will only have ASCII characters, I would use `new int[256]` instead
for (int i = 0; i < str.length(); i++) {
char charAt = str.charAt(i);
counts[(int) charAt]++;
}
for (int i = 0; i < counts.length; i++) {
if (counts[i] > 0)
//System.out.println("Number of " + (char) i + ": " + counts[i]);
System.out.print(""+ counts[i] + (char) i + "");
}
}
}
There are 3 conditions which need to be taken care of:
if (s.charAt(x) != s.charAt(x + 1) && count == 1) ⇒ print the counter and character;
if (s.charAt(x) == s.charAt(x + 1)) ⇒ increase the counter;
if (s.charAt(x) != s.charAt(x + 1) && count >= 2) ⇒ reset to counter 1.
{
int count= 1;
int x;
for (x = 0; x < s.length() - 1; x++) {
if (s.charAt(x) != s.charAt(x + 1) && count == 1) {
System.out.print(s.charAt(x));
System.out.print(count);
}
else if (s.charAt(x)== s.charAt(x + 1)) {
count++;
}
else if (s.charAt(x) != s.charAt(x + 1) && count >= 2) {
System.out.print(s.charAt(x));
System.out.print(count);
count = 1;
}
}
System.out.print(s.charAt(x));
System.out.println(count);
}
The code is really simple.It uses the ASCII value of a character to index into the array that stores the frequency of each character.
The output is simply got by iterating over that array and which character has frequency greater than 1, print it accordingly as you want in the output that is frequency followed by character.
If the input string has same characters consecutive then the solution can be using space of O(1)
For example in your string aabbcc, the same characters are consecutive , so we can take advantage of this fact and count the character frequency and print it at the same time.
for (int i = 0; i < str.length(); i++)
{
int freq = 1;
while((i+1)<str.length()&&str.charAt(i) == str.charAt(i+1))
{++freq;++i}
System.out.print(freq+str.charAt(i));
}
You are trying to keep count of the number of times each character is found. An array is referenced by an index. For example, the ASCII code for the lowercase letter a is the integer 97. Thus the count of the number of times the letter a is seen is in counts[97]. After every element in the counts array has been set, you print out how many have been found.
This should help you understand the basic idea behind how to approach the string compression problem
import java.util.*;
public class LetterCount {
public static void main(String[] args) {
//your input string
String str = "aabbcccddd";
//split your input into characters
String chars[] = str.split("");
//maintain a map to store unique character and its frequency
Map<String, Integer> compressMap = new LinkedHashMap<String, Integer>();
//read every letter in input string
for(String s: chars) {
//java.lang.String.split(String) method includes empty string in your
//split array, so you need to ignore that
if("".equals(s))
continue;
//obtain the previous occurances of the character
Integer count = compressMap.get(s);
//if the character was previously encountered, increment its count
if(count != null)
compressMap.put(s, ++count);
else//otherwise store it as first occurance
compressMap.put(s, 1);
}
//Create a StringBuffer object, to append your input
//StringBuffer is thread safe, so I prefer using it
//you could use StringBuilder if you don't expect your code to run
//in a multithreaded environment
StringBuffer output = new StringBuffer("");
//iterate over every entry in map
for (Map.Entry<String, Integer> entry : compressMap.entrySet()) {
//append the results to output
output.append(entry.getValue()).append(entry.getKey());
}
//print the output on console
System.out.println(output);
}
}
class Solution {
public String toFormat(String input) {
char inChar[] = input.toCharArray();
String output = "";
int i;
for(i=0;i<input.length();i++) {
int count = 1;
while(i+1<input.length() && inChar[i] == inChar[i+1]) {
count+=1;
i+=1;
}
output+=inChar[i]+String.valueOf(count);
}
return output;
}
public static void main(String[] args) {
Solution sol = new Solution();
String input = "aaabbbbcc";
System.out.println("Formatted String is: " + sol.toFormat(input));
}
}
def encode(Test_string):
count = 0
Result = ""
for i in range(len(Test_string)):
if (i+1) < len(Test_string) and (Test_string[i] == Test_string[i+1]):
count += 1
else:
Result += str((count+1))+Test_string[i]
count = 0
return Result
print(encode("ABBBBCCCCCCCCAB"))
If you want to get the correct count considering the string is not in alphabetical order. Sort the string
public class SquareStrings {
public static void main(String[] args) {
SquareStrings squareStrings = new SquareStrings();
String str = "abbccddddbd";
System.out.println(squareStrings.manipulate(str));
}
private String manipulate(String str1) {
//convert to charArray
char[] charArray = str1.toCharArray();
Arrays.sort(charArray);
String str = new String(charArray);
StringBuilder stbuBuilder = new StringBuilder("");
int length = str.length();
String temp = "";
if (length > 1) {
for (int i = 0; i < length; i++) {
int freq = 1;
while (((i + 1) < length) && (str.charAt(i) == str.charAt(i + 1))) {
++freq;
temp = str.charAt(i) + "" + freq;
++i;
}
stbuBuilder.append(temp);
}
} else {
return str + "" + 1;
}
return stbuBuilder.toString();
}
}
Kotlin:
fun compressString(input: String): String {
if (input.isEmpty()){
return ""
}
var result = ""
var count = 1
var char1 = input[0]
for (i in 1 until input.length) {
val char2 = input[i]
if (char1 == char2) {
count++
} else {
if (count != 1) {
result += "$count$char1"
count = 1
} else {
result += "$char1"
}
char1 = char2
}
}
result += if (count != 1) {
"$count$char1"
} else {
"$char1"
}
return result
}
Related
I have this code which compresses characters in the given string and replaces repeated adjacent characters with their count.
Consider the following example:
Input:
aaabbccdsa
Expecting output:
a3b2c2dsa
My code is working properly but I think repeating if condition can be removed.
public class Solution {
public static String getCompressedString(String str) {
String result = "";
char anch = str.charAt(0);
int count = 0;
for (int i = 0; i < str.length(); i++) {
char ch = str.charAt(i);
if (ch == anch) {
count++;
} else {
if (count == 1) { // from here
result += anch;
} else {
result += anch + Integer.toString(count);
} // to here
anch = ch;
count = 1;
}
if (i == str.length() - 1) {
if (count == 1) { // from here
result += anch;
} else {
result += anch + Integer.toString(count);
} // to here
}
}
return result;
}
}
In this solution code below is repeated two times
if (count == 1) {
result += anch;
} else {
result += anch + Integer.toString(count);
}
Please, note, I don't want to use a separate method for repeating logic.
You could do away with the if statements.
public static String getCompressedString(String str) {
char[] a = str.toCharArray();
StringBuilder sb = new StringBuilder();
for(int i=0,j=0; i<a.length; i=j){
for(j=i+1;j < a.length && a[i] == a[j]; j++);
sb.append(a[i]).append(j-i==1?"":j-i);
}
return sb.toString();
}
}
You can do something like this:
public static String getCompressedString(String str) {
String result = "";
int count = 1;
for (int i = 0; i < str.length(); i++) {
if (i + 1 < str.length() && str.charAt(i) == str.charAt(i + 1)) {
count++;
} else {
if (count == 1) {
result += str.charAt(i);
} else {
result += str.charAt(i) + "" + count;
count = 1;
}
}
}
return result;
}
I got rid of the repeated code, and it do as intended.
You can use this approach as explained below:
Code:
public class Test {
public static void main(String[] args) {
String s = "aaabbccdsaccbbaaadsa";
char[] strArray = s.toCharArray();
char ch0 = strArray[0];
int counter = 0;
StringBuilder sb = new StringBuilder();
for(int i=0;i<strArray.length;i++){
if(ch0 == strArray[i]){//check for consecutive characters and increment the counter
counter++;
} else { // when character changes while iterating
sb.append(ch0 + "" + (counter > 1 ? counter : ""));
counter = 1; // reset the counter to 1
ch0 = strArray[i]; // reset the ch0 with the current character
}
if(i == strArray.length-1){// case for last element of the string
sb.append(ch0 + "" + (counter > 1 ? counter : ""));
}
}
System.out.println(sb);
}
}
Sample Input/Output:
Input:: aaabbccdsaccbbaaadsa
Output:: a3b2c2dsac2b2a3dsa
Input:: abcdaaaaa
Output:: abcda5
Since, the body of the else and second if is the same, so we can merge them by updating the condition. The updated body of the function will be:
String result = "";
char anch = str.charAt(0);
int count = 0;
char ch = str.charAt(0); // declare ch outside the loop, and initialize to avoid error
for (int i = 0; i < str.length(); i++) {
ch = str.charAt(i);
if (ch == anch) {
count++;
}
// check if the second condition is false, or if we are at the end of the string
if (ch != anch || i == str.length() - 1) {
if (count == 1) { // from here
result += anch;
} else {
result += anch + Integer.toString(count);
} // to here
anch = ch;
count = 1;
}
}
// add the condition
// if count is greater than or
// if the last character added already to the result
if (count > 1 || (len < 2 || result.charAt(len - 2) != ch)) {
result += ch;
}
return result;
Test Cases:
I have tested the solution on the following inputs:
aaabbccdsa -> a3b2c2dsa
aaab -> a3b
aaa -> a3
ab -> ab
aabbc -> a2b2c
Optional
If you want to make it shorter, you can update these 2 conditions.
if (count == 1) { // from here
result += anch;
} else {
result += anch + Integer.toString(count);
} // to here
as
result += anch;
if (count != 1) { // from here
result += count;// no need to convert (implicit conversion)
} // to here
Here's a single-statement solution using Stream API and regular expressions:
public static final Pattern GROUP_OF_ONE_OR_MORE = Pattern.compile("(.)\\1*");
public static String getCompressedString(String str) {
return GROUP_OF_ONE_OR_MORE.matcher(str).results()
.map(MatchResult::group)
.map(s -> s.charAt(0) + (s.length() == 1 ? "" : String.valueOf(s.length())))
.collect(Collectors.joining());
}
main()
public static void main(String[] args) {
System.out.println(getCompressedString("aaabbccdsa"));
System.out.println(getCompressedString("awswwwhhhp"));
}
Output:
a3b2c2dsa // "aaabbccdsa"
awsw3h3p // "awswwwhhhp"
How does it work
A regular expression "(.)\\1*" is capturing a group (.) of identical characters of length 1 or greater. Where . - denotes any symbol, and \\1 is a back reference to the group.
Method Matcher.results() "returns a stream of match results for each subsequence of the input sequence that matches the pattern".
The only thing left is to evaluate the length of each group and transform it accordingly before collecting into the resulting String.
Links:
A quick tutorial on Regular Expressions.
Official tutorials on lambda expressions and streams
You can use a function which has the following 3 parameters : result, anch, count .
something of this sort:
private static String extractedFunction(String result,int count, char anch) {
return count ==1 ? (result + anch) : (result +anch+Integer.toString(count) );
}
make a function call from those two points like this :
result = extractedFunction(result,count,anch);
Try this.
static final Pattern PAT = Pattern.compile("(.)\\1*");
static String getCompressedString(String str) {
return PAT.matcher(str)
.replaceAll(m -> m.group(1)
+ (m.group().length() == 1 ? "" : m.group().length()));
}
Test cases:
#Test
public void testGetCompressedString() {
assertEquals("", getCompressedString(""));
assertEquals("a", getCompressedString("a"));
assertEquals("abc", getCompressedString("abc"));
assertEquals("abc3", getCompressedString("abccc"));
assertEquals("a3b2c2dsa", getCompressedString("aaabbccdsa"));
}
The regular expression "(.)\\1*" used here matches any sequence of identical characters. .replaceAll() takes a lambda expression as an argument, evaluates the lambda expression each time the pattern matches, and replaces the original string with the result.
The lambda expression is passed a Matcher object containing the results of the match. Here we are receiving this object in the variable m. m.group() returns the entire matched substring, m.group(1) returns its first character.
If the input string is "aaabbccdsa", it will be processed as follows.
m.group(1) m.group() returned by lambda
a aaa a3
b bb b2
c cc c2
d d d
s s s
a a a
Here what I tried
sample input is "aabaa"
eg: in if condition val[0] = a[4]
if it is equal i stored it in counter variable if it is half of the length it original string it is palindrome
if it is not it is not a palindrome
I tried with my basic knowledge in java if there is any errors let me know
boolean solution(String inputString) {
int val = inputString.length();
int count = 0;
for (int i = 0; i<inputString.length(); i++) {
if(inputString.charAt(i) == inputString.charAt(val-i)) {
count = count++;
if (count>0) {
return true;
}
}
}
return true;
}
How about
public boolean isPalindrome(String text) {
String clean = text.replaceAll("\\s+", "").toLowerCase();
int length = clean.length();
int forward = 0;
int backward = length - 1;
while (backward > forward) {
char forwardChar = clean.charAt(forward++);
char backwardChar = clean.charAt(backward--);
if (forwardChar != backwardChar)
return false;
}
return true;
}
From here
In your version you compare first element with last, second with second last etc.
last element in this case is inputString.length()-1(so need to use 'inputString.charAt(val-i-1)' . If you iterate till end, then the count should be equal to length of the string.
for(int i = 0; i<inputString.length(); i++){
if(inputString.charAt(i) == inputString.charAt(val-i-1)){
count ++;
}
}
return (count==val); //true when count=val
Or alternatlively iterate till the mid point of the array, then count value is val/2.
for(int i = 0; i<inputString.length()/2; i++){
if(inputString.charAt(i) == inputString.charAt(val-i-1)){
count ++;
}
}
return (count==val/2); //true when count=val/2
There's no constraints in the question so let me throw in a more cheesy solution.
boolean isPalindrome(String in)
final String inl = in.toLowerCase();
return new StringBuilder(inl).reverse().toString().equals(inl);
}
A palindrome is a word, sentence, verse, or even a number that reads the same forward and backward. In this java solution, we’ll see how to figure out whether the number or the string is palindrome in nature or not.
Method - 1
class Main {
public static void main(String[] args) {
String str = "Nitin", revStr = "";
int strLen = str.length();
for (int i = (strLen - 1); i >=0; --i) {
revStr = revStr + str.charAt(i);
}
if (str.toLowerCase().equals(revStr.toLowerCase())) {
System.out.println(str + " is a Palindrome String.");
}
else {
System.out.println(str + " is not a Palindrome String.");
}
Method - 2
class Main {
public static void main(String[] args) {
int n = 3553, revNum = 0, rem;
// store the number to the original number
int orgNum = n;
/* get the reverse of original number
store it in variable */
while (n != 0) {
remainder = n % 10;
revNum = revNum * 10 + rem;
n /= 10;
}
// check if reversed number and original number are equal
if (orgNum == revNum) {
System.out.println(orgNum + " is Palindrome.");
}
else {
System.out.println(orgNum + " is not Palindrome.");
}
I have written a Java program to find duplicate characters in a string without Hashmap and set.
Below is the program,
package practice;
public class Duplicate {
public static void main(String[] args) {
String src= "abcad";
char[] srcChar= src.toLowerCase().toCharArray();
int len=srcChar.length;
int j=0;
boolean flag=false;
char ch;
// System.out.println("Length of the String is "+len1);
// System.out.println("Length of the character array is "+len);
int k=0;
for(int i=0;i<len;i++)
{
// System.out.println("i-----> "+i + " and character is "+srcChar[i]);
for(j=0;j<len;j++)
{
// System.out.println("j-----> "+j + " and character is "+srcChar[j]);
if(srcChar[i]==srcChar[j])
{
k++;
}
}
if(k>1)
{
if(srcChar[i]>1)
{
System.out.println("This character "+srcChar[i]+" has repeated "+k+ " time");
}
else
{
System.out.println("There are no characters repeated in the given string");
}
}
k=0;
}
}
}
Output here is:
This character a has repeated 2 time
This character a has repeated 2 time
Here, I want the output like
This character a has repeated 2 time
i.e. not repeating the output twice. Since the character "a" is repeated twice, the output is also repeated twice.
kindly help me to get the output once instead of twice.
Thank you,
class PrintDuplicateCharacter
{
public static void main(String[] args)
{
String str = "HelloJava";
char[] ch = str.toCharArray();
int i=0,j=0;
for(i=0;i<ch.length;i++)
{
int count = 0 ;
for( j = i+1;j<ch.length;j++)
{// 4 6 , 8 , 10
if(ch[i] == ch[j] )
{
count++;
}
}
if(count != 0)
{
System.out.print(str.charAt(i) + " Occured " + count + " time");
}
}
}
}
private static void duplicateChar(String str){
char[] arr1 = str.toUpperCase().toCharArray();
int length = str.length();
int count = 1;
String s = "";
char c1 = '\u0000';
for(int i=0;i<length;i++){
count = 1;
for(int j=i+1;j<length;j++){
if(arr1[i] == arr1[j]){
count++;
c1 = arr1[i];
}
if(j == (length-1) && c1 != '\u0000' && !s.contains(String.valueOf(c1))){
s = s+" "+String.valueOf(c1)+" No of times: "+count+"\n";
}
}
}
System.out.println("\nDuplicate char are:\n"+s);
}
You can make a 2 dimensional array, 2 wide, the source strings height. In this array you store a character when it gets replaced and add one to the amount of times it has been replaced.
Something like(I don't know if these counters are correct):
replacements[j][0] = charAt(j);
replacements[j][1] += 1;
You would have to check if the character you are replacing already exists in this array and you can only print elements of the array if they aren't null.
You print this after the original loop.
All you need to fix is to start the second loop from i instead of 0.
for (int i = 0; i < len; i++) {
for (j = i; j < len; j++) {
...
}
...
}
Imports:
import java.util.ArrayList;
import java.util.List;
Code:
public static void main(String args[]) {
String input = "abcad"; // Input value
char[] chars = input.toLowerCase().toCharArray(); // Creates ArrayList
// of all characters
// in the String
List<Character> charR = new ArrayList<>(); // Creates a List used to
// saving the Characters it
// has saved
List<Integer> valR = new ArrayList<>(); // Creates a List that will
// store how many times a
// character is repeated
for (int i = 0; i < chars.length; i++) { // Loop through items in the
// ArrayList
char c = chars[i]; // Create Character value containing the value of
// the item at the "i" index of the ArrayList
if (charR.contains(c)) { // If the List contains item...
for (int i2 = 0; i2 < charR.size(); i2++) { // Loop through its
// items
if (charR.get(i2).equals(c)) { // If you find a match...
valR.set(i2, valR.get(i2) + 1); // Increase repeated
// value by 1
i2 = charR.size(); // Stop loop
} else { // Else...
i2++; // Increase index by 1
}
}
} else { // Else...
charR.add(c); // Add the Character to the List
valR.add(1); // Add the value 1 to the List (Meaning that the
// Character repeated once)
}
}
for (int i = 0; i < charR.size(); i++) { // Loop through all the items
// in the List
System.out.println("'" + charR.get(i) + "' : " + valR.get(i)); // Display
// what
// the
// character
// is
// and
// how
// many
// times
// it
// was
// repeated
}
}
Output:
'a' : 2
'b' : 1
'c' : 1
'd' : 1
char[] array=value.toCharArray();
int count=0;
char ch;
for(int i=0;i<array.length-1;i++)
{
ch=array[i];
count=1;
if(ch!='#'){
for(int j=i+1;j<array.length;j++)
{
if(ch==array[j]){
count++;
array[j]='#';
}
}
if(count>1)
{
System.out.println("char is " + ch + "count" + count);
}
}
}
You can also solve this problem with this code like :
public static void main(String[] args) {
String src = "abcad";
char[] srcChar = src.toLowerCase().toCharArray();
int len = srcChar.length;
int j = 0;
boolean flag = false;
char ch;
// System.out.println("Length of the String is "+len1);
// System.out.println("Length of the character array is "+len);
int k = 0;
for (int i = 0; i < len; i++) {
// System.out.println("i-----> "+i + " and character is "+srcChar[i]);
for (j = 0 + i; j < len; j++) {
// System.out.println("j-----> "+j + " and character is "+srcChar[j]);
if (srcChar[i] == srcChar[j]) {
k++;
}
}
if (k > 1) {
if (srcChar[i] > 1) {
System.out.println("This character " + srcChar[i] + " has repeated " + k + " time");
} else {
System.out.println("There are no characters repeated in the given string");
}
}
k = 0;
}
}
just we need to start the inner loop with j=0+i ;
for (j = 0 + i; j < len; j++)
This will you can observe above code;
I am trying to solve this question: https://www.hackerrank.com/challenges/anagram
Here's my code:
import java.util.*;
public class Anagram {
public static void main(String[] args)
{
Scanner reader = new Scanner(System.in);
int t = reader.nextInt();
while((t--) > 0)
{
String input = reader.nextLine();
if((input.length()) % 2 == 1)
System.out.println(-1);
else
{
int x = input.length();
int q = (int)(Math.floor((x / 2)));
String input1 = input.substring(0, q);
String input2 = input.substring(q, x);
int [] count2 = new int[26];
for(int i = 0; i < input2.length(); i++)
{
char ch2 = input2.charAt(i);
count2[ch2 - 'a']++;
}
// int [] count1 = new int[26];
for(int i = 0; i < input1.length(); i++)
{
char ch1 = input1.charAt(i);
if(count2[i] > 0)
count2[ch1 - 'a']--;
}
int count = 0;
for(int j = 0; j < 26; j++)
{
count = count + Math.abs(count2[j]);
}
System.out.println(count);
}
}
}
}
Sample Input
6
aaabbb
ab
abc
mnop
xyyx
xaxbbbxx
Expected Output
3
1
-1
2
0
1
My output
0
4
1
-1
2
2
Can anyone please tell me where it went wrong? I couldn't find the error...
Your first output always comes 0, because of this line:
int t = reader.nextInt();
followed by reader.nextLine();. Check this post for more details on that. For quick fix, change that line to:
int t = Integer.parseInt(reader.nextLine());
Now, let's start with the below two statements:
int x = input.length();
int q = (int)(Math.floor((x/2)));
No need to do a Math.floor there. x/2 is an integer division, and will give you integer result only.
Moving to the 2nd for loop. You used the following condition:
if(count2[i]>0)
count2[ch1-'a']--;
Notice the mistake there in condition? It should be count2[ch1 - 'a'] > 0. And also, you will miss the case where that count is not greater than 0, in which case you would have to do a ++. BTW, since you're anyways doing a Math.abs(), you don't need the condition. Just do a --:
for( int i = 0; i < input1.length(); i++ ) {
char ch1 = input1.charAt(i);
count2[ch1-'a']--;
}
BTW, the final result would be count / 2, and not count, because count contains the total mismatch from input1 to input2 and vice-versa. But we just have to fix one of them to match the other. So, just consider half the total mismatch.
You can use this to check if two strings are palindromes:
String original = "something";
String reverse = new StringBuilder(original).reverse().toString();
boolean anagram = original.equals(reverse);
As per your question, main logic could be changed to something like below.
Note - I have added only the main logic and excluded the user inputs here.
public static void main(String[] args) {
String str = "acbacccbaac";
int len = str.length();
String str1 = null, str2 = null;
if(len %2 != 0) {//check for odd length
str1 = str.substring(0, len/2);
str2 = str.substring(len/2+1, len);
}else {//check for even length
str1 = str.substring(0, len/2);
str2 = str.substring(len/2, len);
}
char[] arr1 = str1.toLowerCase().toCharArray();
Arrays.sort(arr1);
char[] arr2 = str2.toLowerCase().toCharArray();
Arrays.sort(arr2);
if(Arrays.equals(arr1, arr2))
System.out.println("Yes");
else
System.out.println("No");
}
I implemented this way for the same problem in my HackerRank profile, and works great.
This is my solution to the prob and it works!
static int anagram(String s) {
String a = "";
String b = "";
if (s.length() % 2 == 0) {
a = s.substring(0, s.length() / 2);
b = s.substring((s.length() / 2), s.length());
}
if (s.length() % 2 != 0) {
a = s.substring(0, s.length() / 2);
b = s.substring((s.length() / 2), s.length());
}
if (a.length() == b.length()) {
char[] aArray = a.toCharArray();
char[] bArray = b.toCharArray();
HashMap<Character, Integer> aMap = new HashMap<Character, Integer>();
HashMap<Character, Integer> bMap = new HashMap<Character, Integer>();
for (char c : aArray) { // prepare a Hashmap of <char>,<count> for first string
if (aMap.containsKey(c)) {
aMap.put(c, aMap.get(c) + 1);
} else {
aMap.put(c, 1);
}
}
for (char c : bArray) {// prepare a Hashmap of <char>,<count> for second string
if (bMap.containsKey(c)) {
bMap.put(c, bMap.get(c) + 1);
} else {
bMap.put(c, 1);
}
}
int change = 0;
for (Map.Entry<Character, Integer> entry : bMap.entrySet()) {
System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
if (!aMap.containsKey(entry.getKey())) {
change += entry.getValue();
} else {
if (entry.getValue() > aMap.get(entry.getKey())) {
change += entry.getValue() - aMap.get(entry.getKey());
} else {
//change += entry.getValue();
}
}
}
return change;
} else {
return -1;
}
}
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;
}
}