Swap adjacent characters of string with some conditions - java

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

Related

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.

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

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

How do I avoid exception in the second iteration?

I'm trying to display the number of times a letter appears within a string and outputting it in a new string (compressedString).
For example: aabcccccaaa should display a2b1c5a3.
So far, I got a2 to display only because I've included the break statement. If I took that out, then I would get StringIndexOutOfBoundsException.
My question is: How would I continue going through the whole string to obtain the rest of the aforementioned output without getting StringIndexOutOfBoundsException?
I ran it through debugger but it still isn't clear to me.
public class Problem {
public static void main(String []args) {
String str = "aabcccccaaa";
System.out.println(compressBad(str));
}
public static String compressBad(String str) {
int countConsecutive = 0;
String compressedString = "";
for(int i = 0; i < str.length(); i++) {
countConsecutive++;
if(str.charAt(i) != str.charAt(i + 1)) {
compressedString += "" + str.charAt(i) + countConsecutive;
break;
}
}
return compressedString;
}
}
modify your for loop to terminate when i < str.length() - 1--this is because you are comparing the character at i to the character at i + 1, which makes your loop go out of bounds.
Try this
public class Problem {
public static void main(String []args) {
String str = "aaabc";
System.out.println(compressBad(str));
}
public static String compressBad(String str) {
int countConsecutive = 0;
String compressedString = "";
for(int i = 0; i < str.length(); i++) {
countConsecutive++;
//avoid index out of bounds error
if(str.length() == (i + 1)){
compressedString += ""+ str.charAt(i) + countConsecutive;
countConsecutive = 0;
break;
}
else if(str.charAt(i) != str.charAt(i + 1)){
compressedString += ""+ str.charAt(i) + countConsecutive;
countConsecutive = 0;
}
}
return compressedString;
}
}
The other answers have good solutions, but I thought I would just add what I came up with:
public class Problem {
public static void main(String []args) {
String str = "aabcccccaaa";
System.out.println(compressBad(str));
}
public static String compressBad(String str) {
if (str.length() == 1) return str + "1"; // Handles single character strings
int countConsecutive = 0;
String compressedString = "";
for (int i = 0; i < str.length(); i++) {
if (i > 0) {
countConsecutive++;
if (str.charAt(i) != str.charAt(i-1)) {
compressedString += "" + str.charAt(i-1) + countConsecutive;
countConsecutive = 0;
}
if (i == str.length()-1) {
countConsecutive++; // Needs to be incremented for the last character
compressedString += "" + str.charAt(i) + countConsecutive;
}
}
}
return compressedString;
}
}
Your condition should be like this:
if(i+1 < str.length() && str.charAt(i) != str.charAt(i + 1))
because when you are is at last index of your string then also you are comparing i'th index with i+1 th index.
But after correcting this, still, this code will not give you the expected output.
This is how I would change the code.
public static String compressBad(String str) {
String compressedString = "";
if (str != null && str.length() > 0) {
int countConsecutive = 1;
char prevChar = str.charAt(0);
for (int i = 1; i < str.length(); i++) {
if (str.charAt(i) != prevChar) {
// End of a run. Update compressedString and reset counters
compressedString += String.valueOf(prevChar) + countConsecutive;
prevChar = str.charAt(i);
countConsecutive = 1;
continue;
}
countConsecutive++;
}
compressedString += String.valueOf(prevChar) + countConsecutive;
}
return compressedString;
}
Mukit09 has already mentioned the reason for your StringIndexOutOfBoundsException.
I offer you a more efficient implementation, using String Builder for concatenating strings:
private static String comppressedString(String str) {
if(str == null || str.equals("")) {
return str;
}
if(str.length() == 1) {
return str + "1";
}
StringBuilder sb = new StringBuilder();
sb.append(str.charAt(0)); // Add first letter
int j = 1; // Counter for current sequence length.
for (int i = 0; i < str.length() - 1; i++) {
if(str.charAt(i) != str.charAt(i + 1)) { // end of characters sequence.
sb.append(j); // Add length of previous sequence.
if(j > 1) {
j = 1; // Minimum sequence length is 1
}
sb.append(str.charAt(i+1)); // Add character of next sequence.
} else {
j++; // increase counter, in order to get the length of the current sequence.
}
}
sb.append(j); // Add length of last sequence.
return sb.toString();
}
public static void main(String[] args) {
System.out.println(comppressedString("")); // empty string
System.out.println(comppressedString("a")); // a1
System.out.println(comppressedString("ab")); // a1b1
System.out.println(comppressedString("abba")); // a1b2a1
System.out.println(comppressedString("aabcccccaaa")); // a2b1c5a3
}

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