Java StringTokenizer considering parentheses - java

I am creating a program that tokenizes boolean logic expressions and returns the String array of tokens. The following is my code:
public static String[] tokenize(String s)
{
String delims = "+";
StringTokenizer st = new StringTokenizer(s, delims);
String[] tokens = new String[st.countTokens()];
int i=0;
while (st.hasMoreElements()) {
tokens[i++] = st.nextElement().toString();
}
return tokens;
}
For example, I have the following string as an input:
A+B+(C+D+(A+B))+(B+C)
Using the code I have, it will only generate the following tokens:
A
B
(C
D
(A
B))
(B
C)
Is it possible (using the same structure of code) to come up with these tokens? If not, how is it code-able?
A
B
(C+D+(A+B))
(B+C)

ArrayList<String> tokens = new ArrayList<String>();
String current = "";
int counter = 0;
for(int i = 0 ; i < input.length(); i++)
{
char c = input.charAt(i);
if(counter==0 && c=='+')
{
tokens.add(current);
current = "";
continue;
}
else if(c=='(')
{
counter++;
}
else if(c==')')
{
counter--;
}
current += c;
}
tokens.add(current);
This is the solution for my comment:
You could just loop through 1 character at a time, when you reach a +
while not in a parenthesis, save the characters read up to there, and
start a new set. The way to track if you're in a a set of parentheses
is with a counter. When you hit a open parenthesis, you increment a
counter by 1, when you hit a close parenthesis you decrement the
counter by 1. If the counter > 0 then you're in parentheses. Oh, and
if counter ever goes negative, the string is invalid, and if counter
is not 0 at the end, then the string is also invalid.
You can do the checks on counter and return false or something, to show that it is an invalid string. If you know the string is valid then this works as is. You can get an array from the ArrayList, with tokens.toArray()

If you can find a simple solution go with it otherwise try mine
String s = "A+B+(C+D+(A+B))+(B+C)";
List<String> l = new ArrayList<>();
StringBuilder sb = new StringBuilder();
int p = 0;
for (char c : s.toCharArray()) {
if (c == '(') {
p++;
sb.append(c);
} else if (c == ')') {
p--;
sb.append(c);
} else if (p == 0 && c == '+') {
l.add(sb.toString());
sb.setLength(0);
} else {
sb.append(c);
}
}
if (sb.length() > 0) {
l.add(sb.toString());
}
System.out.println(l);
output
[A, B, (C+D+(A+B))]

Related

Why does Java function return 1 when given ""

I am new to Java. The purpose of the function is to get a word's vowel count. But when given "" as input it returns 1 instead of 0.
Please explain like i am five why this is happening.
public static int getCount(String str) {
String vowels = "aeiou";
int answer = 0;
String strArray[] = str.split("");
for(String chr : strArray) {
if ((vowels.contains(chr)) & (chr != "")) {
answer += 1;
}
}
return answer;
}
I fixed the code by adding if ((vowels.contains(chr)) & (chr != ""))
But this feels ugly
"".split("") returns {""}. If you want to go over the characters, use one of these:
for (char c : str.toCharArray()) {
if (vowels.indexOf(c) != -1) { ... }
}
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (vowels.indexOf(c) != -1) { ... }
}
I prefer the second, it doesn't create a copy of the string.

Replace all doubled or tripled letters with single ones

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.

Infix to Postfix ' StringIndexOutOfBoundsException' error [duplicate]

This question already has an answer here:
What is a StringIndexOutOfBoundsException? How can I fix it?
(1 answer)
Closed 3 years ago.
I am setting up a method that turn a infix string into a postfix equation with a custom LinkStack.
I have tried to to check if the charAt(i) was null and a if statement to check if i is greater than exp.length() but neither worked.
public static String infixToPostfix(String exp)
{
// make variable
String result = new String("");
int temp = 0;
LinkedStack stack = new LinkedStack();
for (int i = 0; i<exp.length(); ++i)
{
char c = exp.charAt(i);
if(Character.isDigit(c))
{
int n = 0;
//extract the characters and store it in num
while(Character.isDigit(c))
{
n = n*10 + (int)(c-'0');
i++;
c = exp.charAt(i); //exception occurs
System.out.println(n);
}
i--;
//push the number in stack
stack.push(n);
//System.out.println(stack.size() + ", Stack size");
}
// If ( push it to the stack.
if (c == '(')
stack.push(c);
// If ) pop and output from the stack
// until an '(' is encountered.
else if (c == ')')
{
while (!stack.isEmpty() && stack.peek() != '(')
result += stack.pop();
if (!stack.isEmpty() && stack.peek() != '(')
return "Invalid Expression"; // invalid expression
else
stack.pop();
}
else // an operator is encountered
{
while (!stack.isEmpty() && pre(c) <= pre((char) stack.peek()))
result += stack.pop();
stack.push(c);
}
}
// pop all the operators from the stack
while (!stack.isEmpty())
result += stack.pop();
String temp2 = stack.print();
System.out.println(temp2);
return result;
}
I expect the output to be 469 645 + if the input is 496+645 but the actual output is java.lang.StringIndexOutOfBoundsException: String index out of range: 7.
while(Character.isDigit(c))
{
n = n*10 + (int)(c-'0');
i++;
c = exp.charAt(i); //exception occurs
System.out.println(n);
}
You aren't length checking here, so you readily parse right off the end of the string.
while(i < exp.length() && Character.isDigit(c))
{
n = n*10 + (int)(c-'0');
if (++i < exp.length()) {
c = exp.charAt(i); //exception occurs
}
System.out.println(n);
}
Note: I'd cache the length because of how many times you use it, but that's not the cause of your problem.
Note, however, that this is cleaner code style:
public class Foo {
public static void main(String[] args) {
String myString = "12345";
int index = 0;
for (char c: myString.toCharArray()) {
System.out.printf("Char at %d == %c\n", index, c);
++index;
}
}
}
Notice the for-loop. I didn't do your calculations or break out or anything, but this is a cleaner way.
You can also do...
for (int index = 0; index < exp.length(); ++index) {
char c = exp.charAt(index);
if (!Character.isDigit(c)) {
break;
}
// Do other stuff here.
}
There are a variety of other ways to structure your code. Your while loop is awkward.

Splitting String by comma and ignore comma in multiple double quotes

I have a String like
value 1, value 2, " value 3," value 4, value 5 " ", value 6
I want to split this by comma and ignoring commas found in an expression enclosed by multiple double quotes
My desired output should be
value 1
value 2
" value 3," value 4, value 5 " "
value 6
I tried this Splitting on comma outside quotes but it doesn't work
Thanks in advance........Elsayed
Well first I would recommend to escape inner double quotes, e. g. value 1, value 2, " value 3,\" value 4, value 5 \" ", value 6. With this sort of syntax a method I use for this purpose is below. It is a little bit more complex than the first proposal, because it ignores blanks and line breaks between a comma and the next element in the list.
public static String[] splitSet(String inStr, char delimiter) {
if (inStr == null)
return null;
if (inStr.isEmpty())
return new String[]{};
/*
* add an empty element here and remove it at the end to simplify
* algorithm
*/
String delimiterStr = String.valueOf(delimiter);
String parseStr = inStr + delimiterStr + " ";
/*
* prepare parsing.
*/
Vector<String> list = new Vector<>();
String element = "";
int lc = 0;
char b = ' ';
char c;
boolean inBetweenQuotes = false;
/*
* parsing loop.
*/
while (lc < parseStr.length()) {
c = parseStr.charAt(lc);
/*
* add current entry and all following empty entries to list vector.
* Ignore space and new line characters following the delimiter.
*/
if ((c == delimiter) && !inBetweenQuotes) {
// flag to avoid adding empty elements for delimiter being blank
// or new line
boolean added = false;
while ((lc < parseStr.length())
&& ((c == delimiter) || (c == ' ') || (c == '\n'))) {
if ((c == delimiter)
&& !(added && ((c == ' ') || (c == '\n')))) {
list.add((String) UFormatter.parseElement(element,
DataType.STRING, delimiterStr));
element = "";
added = true;
}
lc++;
if (lc < parseStr.length())
c = parseStr.charAt(lc);
if (lc > 0)
b = parseStr.charAt(lc - 1);
}
}
/*
* add character to tmpList. Close String literal or Vector literal
*/
else {
element = element + c;
// toggle inBetweenQuotes at not escaped '"'
if ((c == '"') && (b != '\\'))
inBetweenQuotes = !inBetweenQuotes;
lc++;
b = c;
}
}
if (!element.isEmpty() && inBetweenQuotes)
list.add(element.substring(0, element.length() - 1) + "\"");
else if (!element.isEmpty())
list.add(element.substring(0, element.length() - 1));
// put Vector to array.
String[] ret = new String[list.size()];
for (int i = 0; i < list.size(); i++)
ret[i] = list.elementAt(i);
return ret;
}
I don't know how to use regex to solve it.
Is the double quotes included now? I haven't tried this code yet.
public static List<String> splitByComma(String text) {
ArrayList<String> ret = new ArrayList<>();
char[] chars = text.toCharArray();
boolean inQuote = false;
StringBuilder tmp = new StringBuilder();
for (char ch : chars) {
if (ch == ',') {
if (inQuote) tmp.append(ch);
else {
ret.add(tmp.toString());
tmp.setLength(0);
}
} else if (ch == '"') {
tmp.append(ch); // I just add this code
inQuote = !inQuote;
} else tmp.append(ch);
}
ret.add(tmp.toString());
return ret;
}
Please tell me if my code has any problem.

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;
}

Categories

Resources