Replace all doubled or tripled letters with single ones - java

Task:
For a given string of characters consisting only of letters: a, b and
c swap all doubled or tripled letters for single ones
I prepared such a code:
public static String doubleLetters(String str) {
StringBuilder ret = new StringBuilder(str.length());
if (str.length() == 0) return "";
for (int i = 1; i < str.length(); i++)
{
if(str.charAt(i) == str.charAt(i-1)
|| str.charAt(i) == str.charAt(i-1) && str.charAt(i) == str.charAt(i-2))
{
ret.append(str.charAt(i));
}
}
return ret.toString();
}
However, I cannot define the condition to take into account tripled letters.
By entering "aaabbbccc" I want "abc".
By entering "aabbcc" I want "abc".
By entering "aaaaabbbbbbbccc" I want "aabbbc".
IMPORTANT
Letters that are converted to 1 letter are not taken into account.
Please help me how to approach this problem.

It is not entirely clear whether you want to replace only triple or double letters or a repeated character of any length by a single one. I'm assuming the latter one:
public static String eliminateMultipleLetters(String s) {
StringBuilder sb = new StringBuilder(); // better for loops than concatenation
for (int i = 0; i < s.length() - 1; i++) {
if (s.charAt(i) != s.charAt(i + 1))
sb.append(s.charAt(i));
}
sb.append(s.charAt(s.length() - 1)); // append last character
return sb.toString();
}
Edit: to replace 3 characters by 1 as long as there are 3 and then 2 if possible, you could do as follows (the logic is very similar, just the step at the end gets more complicated):
public static String replace3or2Letters(String s) {
if (s.length() < 2)
return s;
StringBuilder sb = new StringBuilder();
int i;
for (i = 0; i < s.length() - 2; i++) {
sb.append(s.charAt(i));
if (s.charAt(i) == s.charAt(i + 1)) {
if (s.charAt(i) == s.charAt(i + 2))
i += 2;
else
i++;
}
}
if (i == s.length() - 2) {
sb.append(s.charAt(s.length() - 2));
if (s.charAt(s.length() - 2) != s.charAt(s.length() - 2))
sb.append(s.charAt(s.length() - 1));
} else if (i == s.length() - 1) {
sb.append(s.charAt(s.length() - 1));
}
return sb.toString();
}
More elegant:
public static String replaceUpToXbySingle(String s, int x) { // x = 3 for you
StringBuilder sb = new StringBuilder();
char last = 'c'; // whatever
int count = 0;
for (int i = 0; i < s.length(); i++) {
if (count == 0 || s.charAt(i) != last) {
if (count > 0)
sb.append(last);
last = s.charAt(i);
count = 1;
} else if (++count == x) {
sb.append(last);
count = 0;
}
}
if (count > 0)
sb.append(last);
return sb.toString();
}

Updated response
If you want to replace groups of three, followed by groups of two, you need to build a list of contiguous frequencies. After you have this list, you could build a string by applying div/mod logic to the total.
I included a Pair class that extends Map.Entry which stores key-value associations.
import java.util.*;
public class StringUtil {
public static void main(String[] args) {
System.out.println(dedupe("aabbcc").equals("abc"));
System.out.println(dedupe("aaabbbccc").equals("abc"));
System.out.println(dedupe("aaaaabbbbbbbccc").equals("aabbbc"));
}
public static String dedupe(String str) {
if (str == null || str.isEmpty()) {
return str;
}
StringBuilder buffer = new StringBuilder();
List<Pair<Character, Integer>> pairs = new ArrayList<>();
char[] chars = str.toCharArray();
char curr, prev = chars[0];
int total = 0, i, add3, add2;
for (i = 1; i < chars.length; i++) {
curr = chars[i];
total++;
if (curr != prev) {
pairs.add(new Pair<>(prev, total));
total = 0;
prev = curr;
}
}
total++;
pairs.add(new Pair<>(prev, total));
for (Pair<Character, Integer> pair : pairs) {
total = pair.getValue();
add3 = total / 3;
for (i = 0; i < add3; i++) {
buffer.append(pair.getKey());
}
total %= 3;
add2 = total / 2;
for (i = 0; i < add2; i++) {
buffer.append(pair.getKey());
}
total %= 2;
for (i = 0; i < total; i++) {
buffer.append(pair.getKey());
}
}
return buffer.toString();
}
private static final class Pair<K, V> implements Map.Entry<K, V> {
private final K key;
private V value;
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
#Override
public K getKey() {
return key;
}
#Override
public V getValue() {
return value;
}
#Override
public V setValue(V value) {
V old = this.value;
this.value = value;
return old;
}
}
}
Original response
All you would need to do it store a previous (prev) value and then just loop over the characters and append to buffer if current (curr) does not match the previous.
public class StringUtil {
public static void main(String[] args) {
System.out.println(dedupe("aaabbbccc")); // "abc"
}
public static String dedupe(String str) {
StringBuilder buffer = new StringBuilder();
char prev = 0;
for (char curr : str.toCharArray()) {
if (curr != prev) {
buffer.append(curr);
prev = curr;
}
}
return buffer.toString();
}
}

Another approach: count the number of consecutive occurrences of a character, and then print them in bulk, by dividing their number by three.
public static String doubleLetters(String str) {
StringBuilder ret = new StringBuilder(str.length());
if (str.length() == 0) return "";
int count = 1;
for (int i = 1; i < str.length(); i++)
{
if (str.charAt(i) == str.charAt(i-1)) {
count++;
continue;
}
for (; count > 0; count -= 3)
ret.append(str.charAt(i-1));
count = 1;
}
for (; count > 0; count -= 3)
ret.append(str.charAt(str.length() - 1));
return ret.toString();
}

However, I cannot define the condition to take into account tripled
letters.
By entering "aaabbbccc" I want "abc".
By entering "aabbcc" I want "abc".
By entering "aaaaabbbbbbbccc" I want "aabbbc".
IMPORTANT Letters that are converted to 1 letter are not taken into
account.
Imagine this problem in three stages:
First, generate a sequence (or a stream) of all the single, double, or triple letter occurrences in your input
Next, replace each of the occurrences in the sequence with its first letter
Finally, put the sequence (or stream) back together into a single String instance
To realize this solution very readably, I would use a main method and a static helper method as follows:
public static String deDupe(String input) {
String result = generateStreamOfOccurrences(input)
.map(occurrence -> occurrence.substr(0, 1)
.collect(Collectors.joining());
return result;
}
private static Stream<String> generateStreamOfOccurrences(String input) {
List<String> listOfOccs = new ArrayList<>();
if (input != null) {
while (input.length() > 0) {
String occ = input.substring(0, 1);
if (input.length() > 2 && input.substring(1, 3).equals(occ + occ))
occ = input.substring(0, 3);
if (input.length() > 1 && input.substring(1, 2).equals(occ))
occ = input.substring(0, 2);
input = input.substring(occ.length());
listOfOccs.add(occ);
}
}
return listOfOccs.stream();
}
The main function is easy to read. It obtains a stream of letter occurrences in the String, each of which is a single, double, or triple of its first letter. The work of obtaining this Stream<String> pipeline is encapsulated in the helper function generateListOfOccurrences().

However, I cannot define the condition to take into account tripled
letters.
By entering "aaabbbccc" I want "abc".
By entering "aabbcc" I want "abc".
By entering "aaaaabbbbbbbccc" I want "aabbbc".
IMPORTANT Letters that are converted to 1 letter are not taken into
account.
Imagine this problem in three stages:
First, generate a sequence (or a stream) of all the single, double, or triple letter occurrences in your input
Next, replace each of the occurrences in the sequence with its first letter
Finally, put the sequence (or stream) back together into a single String instance
To realize this solution very readably, I would use a main method and a static helper method as follows:
public static String deDupe(String input) {
String result = generateStreamOfOccurrences(input)
.map(occurrence -> occurrence.substring(0, 1)
.collect(Collectors.joining());
return result;
}
private static Stream<String> generateStreamOfOccurrences(String str) {
String input = str;
List<String> listOfOccs = new ArrayList<>();
if (input != null) {
while (input.length() > 0) {
String occ = input.substring(0, 1);
if (input.length() > 2 && input.substring(1, 3).equals(occ + occ)) {
occ = input.substring(0, 3);
}
else if (input.length() > 1 && input.substring(1, 2).equals(occ)) {
occ = input.substring(0, 2);
}
input = input.substring(occ.length());
listOfOccs.add(occ);
}
}
return listOfOccs.stream();
}
The main function is easy to read. It obtains a stream of letter occurrences in the String, each of which is a single, double, or triple of its first letter. The work of obtaining this Stream<String> pipeline is encapsulated in the helper function generateListOfOccurrences(). Then each of the elements in the stream are replaced by elements that consist of just the 1st letter. Then they are joined together to form the result.

Related

Swap adjacent characters of string with some conditions

import java.io.*;
import java.util.*;
public class Test
{
public static String solve(String str) {
String result = "Invalid string"; // prepare result
if (null != str && str.length() % 2 == 0) { // check the null and length of the input
char[] arr = str.toCharArray();
for (int i = 0; i < arr.length; i += 2) {
if (Character.isDigit(arr[i]) || Character.isDigit(arr[i + 1])) {
// if any digit found, return "Invalid string"
return result;
}
// do the swap
char t = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = t;
}
// make the result string
result = new String(arr);
}
return result;
}
public static void main(String[] args) throws Exception
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int t = Integer.parseInt(br.readLine());
for(int i = 0; i < t; i++)
{
String str = br.readLine();
try
{
System.out.println(solve(str));
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
}
}
}
Only perform the swapping if length of string is even and does not contain numeric value.
if string contain numeric value then throw exception invalid input. if string length is odd then throw exception invalid length.
Test Cases :
INPUT:
4 ( represent the number of test-cases)
afafas
ajanta
sdf
sasfd3sf
OUTPUT:
fafasa
janaat
invalid string length
invalid input
Therefore swapping will be perform keep in mind these scenarios
Your code needs a little correction which I have pointed out below.
public static String solve(String str) {
String result = "invalid string length"; // prepare result if the length is not correct
if (null != str && str.length() % 2 == 0) { // check the null and length //of the input
char[] arr = str.toCharArray();
for (int i = 0; i < arr.length; i += 2) {
if (Character.isDigit(arr[i]) || Character.isDigit(arr[i + 1])) {
// if any digit found, return "Invalid string"
return "invalid input"; // return this as digit is found
}
// do the swap
char t = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = t;
}
// make the result string
result = new String(arr);
}
return result;
}
I ran the above program the above test case falied are for last two cases only. The result statement alone want to be changed.by default it has given -- Invalid string
If length is odd it should print -- invalid string length
If the string contains digit it should print -- invalid input
public static String solve(String str) {
String result; // prepare result
if (null != str && str.length() % 2 == 0) { // check the null and length of the input
char[] arr = str.toCharArray();
for (int i = 0; i < arr.length; i += 2) {
if (Character.isDigit(arr[i]) || Character.isDigit(arr[i + 1])) {
// if any digit found, return "Invalid string"
result = "invalid input";
return result;
}
// do the swap
char t = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = t;
}
// make the result string
result = new String(arr);
}
else {
result ="invalid string length";
}
return result;
}

How do I check if a string contains all repeated letters in Java?

For example the string abba contains all repeated letters, for this kinds of strings I need to be able to return a certain value. I have the following code, but this only tells me if strings like "aaaa" contain ALL the same letters, and doesn't work for strings containing repeating letters of two types.
public static boolean checkAllRepeated(String input)
{
char[] chars = input.toCharArray();
int[] counts = new int[chars.length];
int n = input.length();
for (int i = 1; i < n; i++)
if (chars[i] != chars[0])
return false;
return true;
}
If I understand correctly, you want your function to return false if your input string contains characters which occur only once?
public static boolean checkAllRepeated(String input)
{
Map<Character, Integer> map = new HashMap<>();
for (Character c : input.toCharArray()){
map.putIfAbsent(c, 0);
map.put(c, map.get(c)+1);
}
return map.values().stream().noneMatch(i -> i == 1);
}
A map should make it easy,
String input = "aabbcc";
Map<Character, Integer> unique = new HashMap<>();
for(Character aChar : input.toCharArray()){
if(unique.get(aChar) != null) {unique.put(aChar, unique.get(aChar) + 1);}
else { unique.put(aChar, 1); }
}
if(unique.containsValue(1)){System.out.println("no duplicates"); }
for a String where only one char is not repeated i.e. occurrence of one character is odd then you can follow the XOR operation
public char solution(char[] cs) {
if (cs.length > 0) {
int i;
int res = 0;
for (i = 0; i < cs.length; i++) {
res = res ^ cs[i];
}
return (char) res;
}
return (char) -1;
}
as i understand if just one character not repeated then return false, this will work for that purpose.
public static boolean checkAllRepeated(String input)
{
char[] chars = input.toCharArray();
int counts;
int n = input.length();
for (int i = 1; i < n; i++){
counts =1;
for (int j = 0; j < n; j++){
if (j != i && chars[i] == chars[j]) counts++;
}
if(counts==1)return false;
}
return true;
}

Using for loop and charAt to check if each letter appears exactly twice in a word

i'm writing a program in java that checks if a letter appers exactly twice, i was able to write it but my problem is that for some words the code doesn't check if the letter appear exactly twice.
here is my code:
public class Test {
public static void main(String[] args) {
isDoubloon("abba");
isDoubloon("Shanghaiingss");/*it still prints out true though 's' does appear exactly twice*/}
//checks if every letter appears twice in a word
public static void isDoubloon(String s){
String l=s.toLowerCase();
int count=0;
for(int i= 0; i<l.length()-1;i++){
for(int j=i+1;j<l.length();j++){
if(l.charAt(i)==l.charAt(j)) count++;
}
}
if(count%2==0){
System.out.println("True, This is a doubloon");
}else
System.err.println("False, This is not a doubloon");
}}
Your whole logic is not correct. You have to check for every letter in your text if it occurs twice.
Try this:
String l=s.toLowerCase();
boolean check = true;
for(int i= 0; i<l.length();i++){
int count=0;
for(int j=0;j<l.length();j++){
if(l.charAt(i)==l.charAt(j)) count++;
}
if (count != 2) {
check = false;
break;
}
}
if(check==true){
System.out.println("True, This is a doubloon");
}else
System.out.println("False, This is not a doubloon");
}
Your code counts how often each letter occurs (-1) and adds all this values. If the result is even you imply that each letter is exactly twice in the word. That cannot work.
Simply try the word "aaabbbb". (your code think it is a doubloon)
So you need to check if no character occurs exactly twice and that for each character separately.
You could do it this way:
public static void main(String[] args) {
if(isDoubloon("Shanghaiingss")){
System.out.println("True, This is a doubloon");
}else{
System.err.println("False, This is not a doubloon");
}
}
public static boolean isDoubloon(final String s) {
final String l = s.toLowerCase();
for (int i = 0; i < l.length(); i++) {
int count = 0;
for (int j = 0; j < l.length(); j++) {
if (l.charAt(i) == l.charAt(j)) {
count++;
if (2 < count) {
return false; // more than twice
}
}
}
if (1 == count) {
return false; // character occurs only once
}
}
return true;
}
This algorithm is similar to yours. But it is far from fast O(n²). Is you need it you can implement it faster O(n) but you would need some extra space.
The main flaw here is that you are using a single "count" variable when you want to do a count for each letter.
I would suggest using a map to hold a count for each letter, loop over the list and add each letter to your map and finally iterate over the map and confirm all values are 2.
public static void isDoubloon(String s){
String l=s.toLowerCase();
Map<Character, Integer> counts = new HashMap();
for(int i= 0; i<l.length()-1;i++){
int prevValue = counts.getOrDefault(l.charAt(i), 0);
counts.put(l.charAt(i), prevValue + 1);
}
for (Map.Entry<Character, Integer> entry: counts.entrySet()) {
if (entry.getValue() != 2) {
System.err.println("False, This is not a doubloon");
}
}
System.out.println("True, This is a doubloon");
}
Other solution
private boolean isDoubloon(String s) {
String convertWord = s.toLowerCase();
char[] letter = convertWord.toCharArray();
int[] count = new int[26];
for (int letters = 0; letters < letter.length; letters++) {
char index = letter[letters];
count[index - 97]++;
}
for( int i = 0; i < 26; i++ ) {
if (count[i] != 0 && count[i] != 2) return false;
}
return true;
}
public static boolean isDoubloon(String s) {
if (s.length() %2 != 0)
return false;
String str = s.toLowerCase();
while (str.length() > 0) {
int index2 = str.indexOf(str.charAt(0), 1);
if (index2 == -1) {
return false;
}
int index3 = str.indexOf(str.charAt(0), index2 + 1);
if (index3 != -1) {
return false;
}
str = str.substring(1, index2) + str.substring(index2 + 1);
}
return true;
}
Obligatory Java Streams examples:
groupingBy() and counting()
public static boolean isDoubloon(String str) {
return
// Stream over chars, and box to Integer
// These will be the ASCII values of the chars
!str.chars().boxed()
// Group by identity
.collect(Collectors.groupingBy(Function.identity(),
// and map each key to the count of characters
Collectors.counting()))
// We now have a Map<Integer, Long>, the Integer being the character
// value and the Long being the number of occurrences.
// Stream over the Map's values
.values().stream()
// Retain all values unequal to 2
.filter(i -> !Objects.equals(i, 2L))
// Shortcut if found and check if a value is present
.findAny().isPresent();
// If a value is present, that means that there are one or more
// characters with less or more than two occurrences.
}
https://ideone.com/PT8sQi
distinct() and count()
public static boolean isDoubloon(String str) {
long distinct = str.chars().distinct().count();
long length = str.length();
return (length % 2 == 0 && length / 2 == distinct);
}
https://ideone.com/UaOKDF

How to replace a char in a string without using Replace() in Java?

I've been having trouble with this assignment:
Given a string, replace the first occurrence of 'a' with "x", the second occurrence of 'a' with "xx" and the third occurrence of 'a' with "xxx". After the third occurrence, begin the replacement pattern over again with "x", "xx", "xxx"...etc.; however, if an 'a' is followed by more than 2 other 'a' characters in a row, then do not replace any more 'a' characters after that 'a'.
No use of the replace method is allowed.
aTo123X("ababba") → "xbxxbbxxx"
aTo123X("anaceeacdabnanbag") → "xnxxceexxxcdxbnxxnbxxxg"
aTo123X("aabaaaavfaajaaj") → "xxxbxxxaaavfaajaaj"
aTo123X("pakaaajaaaamnbaa") → "pxkxxxxxxjxxaaamnbaa"
aTo123X("aaaak") → "xaaak"
My code's output is with a's included, x's added but not the correct amount of x's.
public String aTo123X(String str) {
/*
Strategy:
get string length of the code, and create a for loop in order to find each individual part of the String chars.check for a values in string and take in pos of the a.
if one of the characters is a
replace with 1 x, however, there aren't more than 2 a's immediately following first a and as it keeps searching through the index, add more x's to the original string, but set x value back to 1 when x reaches 3.
if one of characters isn't a,
leave as is and continue string.
*/
String xVal = "";
String x = "x";
String output = "";
for (int i = 0; i < str.length(); i++){
if( str.charAt(i) == 'a'){
output += x;
str.substring(i+1, str.length());
}
output += str.charAt(i);
}
return output;
}
This is the code that does the same. I've commented the code to explain what it does
public class ReplaceChar {
public static void main(String... args){
String[] input =new String[]{"ababba","anaceeacdabnanbag","aabaaaavfaajaaj"};
StringBuilder result = new StringBuilder();
for (int i= 0; i < input.length;i++){
result.append(getReplacedA(input[i]));
result.append("\n");
}
System.out.println(result);
}
private static String getReplacedA(String withA){
// stringBuilder for result
StringBuilder replacedString = new StringBuilder();
// counting the number of time char 'a' occurred in String for replacement before row of 'aaa'
int charACount = 0;
// get the first index at which more than two 'aa' occurred in a row
int firstIndexOfAAA = withA.indexOf("aaa") + 1;
// if 'aaa' not occurred no need to add the rest substring
boolean addSubRequired = false;
// if the index is 0 continue till end
if (firstIndexOfAAA == 0)
firstIndexOfAAA = withA.length();
else
addSubRequired = true;
char[] charString = withA.toCharArray();
//Replace character String[] array
String[] replace = new String[]{"x","xx","xxx"};
for(int i = 0; i < firstIndexOfAAA; i++){
if (charString[i] == 'a'){
charACount++;
charACount = charACount > 3 ? 1 : charACount ;
// add the number x based on charCount
replacedString.append(replace[charACount - 1]);
}else{
replacedString.append(charString[i]);
}
}
// if the String 'aaa' has been found previously add the remaining subString
// after that index
if (addSubRequired)
replacedString.append(withA.substring(firstIndexOfAAA));
// return the result
return replacedString.toString();
}
}
Output:
xbxxbbxxx
xnxxceexxxcdxbnxxnbxxxg
xxxbxxxaaavfaajaaj
EDIT : Some Improvement You can make for some corner cases in the getReplacedA() function:
Check if char 'a' is there or not in the String if not just return the String No need to do anything further.
Use IgnoreCase to avoid the uppercase or lowercase possibility.
Firstly, string is immutable, so the below statement does nothing
str.substring(i+1, str.length());
I guess you wanted to do:
str = str.substring(i+1, str.length());
However, even after fix that, your program still doesn't work. I can't really comprehend your solution. 1) you are not detecting more than 3 a's in a row. 2) you are not appending "xx" or "xxx" at all
Here is my version, works for me so far:
public static void main(String[] args) {
System.out.println(aTo123X("ababba")); // "xbxxbbxxx"
System.out.println(aTo123X("anaceeacdabnanbag")); // "xnxxceexxxcdxbnxxnbxxxg"
System.out.println(aTo123X("aabaaaavfaajaaj")); // "xxxbxxxaaavfaajaaj"
}
public static String aTo123X(String str) {
String output = "";
int aOccurrence = 0;
String[] xs = {"x", "xx", "xxx"};
for (int i = 0; i < str.length(); ++i) {
if (str.charAt(i) == 'a') {
output += xs[aOccurrence % 3]; // append the x's depending on the number of a's we have seen, modulus 3 so that it forms a cycle of 3
if (i < str.length() - 3 && str.charAt(i + 1) == 'a' && str.charAt(i + 2) == 'a' && str.charAt(i + 3) == 'a') {//if an 'a' is followed by more than 2 other 'a' characters in a row
output += str.substring(i + 1);
break;
} else {
++aOccurrence; // increment the a's we have encountered so far
}
} else {
output += str.charAt(i); // append the character if it is not a
}
}
return output;
}
public class NewClass {
public static void main(String[] args) {
System.out.println(aTo123X("ababba")); // "xbxxbbxxx"
System.out.println(aTo123X("anaceeacdabnanbag")); // "xnxxceexxxcdxbnxxnbxxxg"
System.out.println(aTo123X("aabaaaavfaajaaj")); //xxxbxxxaaavfaajaaj
}
public static String aTo123X(String str) {
String output = "";
int aCount = 0;
int inRow = 0;
for (int i = 0; i < str.length();) {
if (str.charAt(i) == 'a') {
if (inRow <= 1) {
inRow++;
aCount++;
if (aCount == 1) {
output += "x";
} else if (aCount == 2) {
output += "xx";
} else {
output += "xxx";
aCount = 0;
}
boolean multiple = ((i + 1) < str.length()) && (str.charAt(i + 1) == 'a')
&& ((i + 2) < str.length()) && (str.charAt(i + 2) == 'a');
if (multiple) {
i++;
while (i < str.length()) {
output += str.charAt(i++);
}
return output;
}
} else {
output += str.charAt(i);
}
} else {
output += str.charAt(i);
inRow = 0;
}
i++;
}
return output;
}
}
I am pointing out problems in your code in form of comments in the code itself.
public String aTo123X(String str) {
//You are not using xVal variable in your code, hence it's obsolete
String xVal = "";
//You don't need x variable as you can simply use string concatenation
String x = "x";
String output = "";
for (int i = 0; i < str.length(); i++) {
/**
* Here, in "if" block you have not implmented any logic to replace the 2nd and
* 3rd occurence of 'a' with 'xx' and 'xxx' respectively. Also, substring() returns
* the sub-string of a string but you are not accepting that string anywhere, and
* you need not even use sub-string as "for" loop will cycle through all the
* characters in the string. If use sub-string method you code will only process
* alternative characters.
*/
if( str.charAt(i) == 'a') {
output += x;
str.substring(i+1, str.length());
}
/**
* Because of this statement a's are also returned, because this statement gets
* in both scenarios, whether the current character of string is a or not.
* But, this statement should get executed only when current character of the
* string is 'a'. So, in terms of coding this statement gets executed no matter
* "if" loop is executed or not, but it should get executed only when "if" loop
* is not executed. So, place this statement in else block.
*/
output += str.charAt(i);
}
return output;
}
I have implemented the logic for you. Here is Solution for your problem, just copy and run it. It passes all the specified test cases.
public String aTo123X(String str) {
String output = "";
int count = 1;
boolean flag = true;
for (int i = 0; i < str.length(); i++) {
if(str.charAt(i) == 'a' && flag == true) {
switch(count) {
case 1: output += "x";
count++;
break;
case 2: output += "xx";
count++;
break;
case 3: output += "xxx";
count = 1;
break;
}
if ((str.charAt(i+1) == 'a' && str.charAt(i+2) == 'a') == true) {
flag = false;
}
}
else {
output += str.charAt(i);
}
}
return output;
}
I use Map To store where to replace
public static void main(String[] args) {
System.out.println(aTo123X("ababba"));//xbxxbbxxx
System.out.println(aTo123X("anaceeacdabnanbag"));//xnxxceexxxcdxbnxxnbxxxg
System.out.println(aTo123X("aabaaaavfaajaaj"));//xxxbxxxaaavfaajaaj
}
public static String aTo123X(String str){
String res = "";
int nthReplace = 1; //Integer to store the nth occurence to replace
//Map to store [key == position of 'a' to replace]
//[value == x or xx or xxx]
Map<Integer, String> toReplacePos = new HashMap<>();
//The loop to know which 'a' to replace
for (int i = 0; i < str.length(); i++) {
if(str.charAt(i) == 'a'){
toReplacePos.put(i, nthReplace % 3 == 1 ? "x": (nthReplace % 3 == 2 ? "xx": "xxx"));
nthReplace++;
//Break if an 'a' is followed by more than 2 other 'a'
try {
if((str.charAt(i+1) == 'a')
&& (str.charAt(i+2) == 'a')
&& (str.charAt(i+3) == 'a')){
break;
}
} catch (StringIndexOutOfBoundsException e) {
}
}
}
//Do the replace
for (int i = 0; i < str.length(); i++) {
res += toReplacePos.containsKey(i) ? toReplacePos.get(i) : str.charAt(i);
}
return res;
}
I have edited my answer. This one is giving the correct solution:
public static void main (String[] args) throws InterruptedException, IOException, JSONException {
System.out.println(aTo123X("ababba")); //xbxxbbxxx
System.out.println(aTo123X("anaceeacdabnanbag")); //xnxxceexxxcdxbnxxnbxxxg
System.out.println(aTo123X("aabaaaavfaajaaj")); //xxxbxxxaaavfaajaaj
}
public static String aTo123X(String str) {
String x = "x";
String xx = "xx";
String xxx = "xxx";
int a = 1;
int brek = 0;
String output = "";
for (int i = 0; i < str.length(); i++) {
if(str.charAt(i) == 'a' && a == 1) {
output += x;
str.substring(i+1, str.length());
a = 2;
try {
if(str.charAt(i+1) == 'a' && str.charAt(i+2) == 'a')
brek += 1;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else if(str.charAt(i) == 'a' && a == 2) {
output += xx;
str.substring(i+1, str.length());
a = 3;
try {
if(str.charAt(i+1) == 'a' && str.charAt(i+2) == 'a')
brek += 1;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else if(str.charAt(i) == 'a' && a == 3) {
output += xxx;
str.substring(i+1, str.length());
a = 1;
try {
if(str.charAt(i+1) == 'a' && str.charAt(i+2) == 'a')
brek += 1;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else {
output += str.charAt(i);
brek = 0;
}
if(brek>0) {
output += str.substring(i+1);
break;
}
}
return output;
}

Return the sum of all integers from a random String without using regex

I was asked this question in an interview recently (Java programming que)
Return the sum of all integers from a random String.
Just iterate over the string, handle one digit at a time. This is pretty much exactly what the regex would do anyway:
String testStrings[] = { "-1a2b3c", "123ab!45c", "abcdef", "0123.4",
"dFD$#23+++12##T1234;/.,10" };
for (String testString : testStrings) {
String currentNumber = "";
int sum = 0;
for (int i = 0; i < testString.length(); i++) {
char currentChar = testString.charAt(i);
// Add digits or a leading minus to "currentNumber"
if (Character.isDigit(currentChar)
|| (currentNumber.equals("") && currentChar == '-')) {
currentNumber += currentChar;
} else {
// We've stumbled across a non-digit char.
//Try to parse the "currentNumber" we have so far
if (!currentNumber.equals("") && !currentNumber.equals("-"))
sum += Integer.parseInt(currentNumber);
currentNumber = "";
}
}
// Add the last "currentNumber" in case the string ends with a
// number
if (!currentNumber.equals("") && !currentNumber.equals("-"))
sum += Integer.parseInt(currentNumber);
System.out.println(sum);
}
Output:
4
168
0
127
1279
public class Random {
public int SumofNumbers(String s){
char[] str = s.toCharArray();
String answer="";
int sum = 0;
List<String> al = new ArrayList();
for (int i=0;i< str.length;i++){
if (checkNumber(str[i])){
answer=answer+str[i];
}
else
{
if(!answer.isEmpty()){
al.add(answer);
answer = "";
}
}
if (i == str.length -1 && !answer.isEmpty()) {
al.add(answer);
}
}
for (String a1 : al){
sum = sum + Integer.valueOf(a1);
}
return sum;
}
private boolean checkNumber(char c) {
if ((int)c > 47 && (int)c < 58){
return true;
}else if ((int)c == 45){
return true;
}
return false;
}
public static void main(String [] args){
Random r = new Random();
String test = "123ab!45c";
System.out.println(r.SumofNumbers(test));
}
}
public class StringToIntAddition {
public static void main(String[] args) throws Exception {
String str = "2e40 ssdf 23-9", number="";
int sum=0;
for(int i=0; i<str.length() ;i++){
if(Character.isDigit(str.charAt(i))){
number += str.charAt(i);
}
else if(!number.isEmpty()){
sum += Integer.parseInt(number);
number= "";
}
if (str.charAt(i) == '-'){
number = "-" ;
}
}
if(!number.isEmpty()){
sum += Integer.parseInt(number);
}
System.out.println("number= " + sum);
}
}
I've got a slightly 'cute' way to do this in Java 8: implement it as a Collector
public DigitCollector {
private boolean negative = false;
private int current = 0;
private int total = 0;
public int getTotal() {
if (negative) {
total -= current;
} else {
total += current;
}
current = 0;
negative = false;
return total;
}
public void accept(Character ch) {
if (Character.isDigit(ch)) {
current = 10 * current + Integer.parseInt(ch.toString());
} else if (ch.equals('-')) {
negative = true;
} else {
getTotal();
}
}
}
Now you can collect a stream of characters:
text.chars().map(ch -> new Character((char)ch))
.collect(DigitCollector::new, DigitCollector::accept, null)
.getTotal();
I realise the mapping ch -> new Character((char)ch)) looks strange but .chars() returns a stream of integers instead of characters. See here for reasons why (though pretty much everyone agrees it was a mistake).
This is a slightly longwinded way of doing it but it's pretty flexible: you could take a stream of Character from anywhere and do any sort of manipulation you wanted before collecting them. It seems to me to be a natural representation of the problem and, mostly, I just reckon streams are cooler than traditional iteration :-)
There's already quite a few answers, but this one seemed fun. I have a different solution that should be pretty efficient:
public static int countString(String input) {
if (input == null) return 0;
int sum = 0;
int accumulator = 0;
boolean lastCharWasDigit = false;
for (int i = 0, len = input.length(); ++i) {
char c = input.charAt(i);
// If a non-digit character is found, clear the
// accumulator and add it to the sum.
if (c < '0' || c > '9') {
sum += accumulator;
accumulator = 0;
lastCharWasDigit = false;
continue;
}
// If the previous character was a digit, that means
// this is a continuation. Multiply by ten to shift
// it over one power of ten before adding the new value
if (lastCharWasDigit) {
accumulator *= 10;
}
// Add the integer value of the character
int charValue = c - '0';
accumulator += charValue;
lastCharWasDigit = true;
}
// Finally, clear the accumulator for any ending digits,
// and return the sum
sum += accumulator;
return sum;
}

Categories

Resources