I expect the User to provide a sentence.
And as an output, they will reverse a string with only the odd-length words reversed (i.e. even-length words should remain intact).
static String secretAgentII(String s) {
StringBuffer sb = new StringBuffer();
String[] newStr = s.split(" ");
String result = "";
for (int i = 0; i < newStr.length; i++) {
if (newStr[i].length() % 2 != 0) {
sb.append(newStr[i]).reverse();
result += sb + " ";
}
result += newStr[i] + " ";
}
return result;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
System.out.println(secretAgentII(s));
}
Input:
One two three Four
Expected Output:
enO owT eerhT Four
The actual Output:
enO One owtOne two eerhtenOtwo three Four
How can I fix that?
I went ahead and wrote a method for what I think you are asking for.
public static String secretAgentII(String input){
StringBuilder returnValue = new StringBuilder();
input = input.replaceAll(" +", " ");
String[] tempArray = input.split(" ");
for (int i = 0; i < tempArray.length; i++) {
String currentString = tempArray[i];
if (currentString.length() % 2 == 1) {
char[] tempArrayOfStringChars = currentString.toCharArray();
for (int j = tempArrayOfStringChars.length - 1; j >= 0; j--) {
returnValue.append(tempArrayOfStringChars[j]);
}
} else {
returnValue.append(currentString);
}
if (i != tempArray.length - 1) { //This prevents a leading space at the end of your string
returnValue.append(' ');
}
}
return returnValue.toString();
}
From what I could tell, you only want the words of odd length to be reversed.
My sample input and output was as follows.
Input: One two three four five six seven eight nine ten
Output: enO owt eerht four five xis neves thgie nine net
Your problem is that you add to result the whole sb, instead of just the current reverse word. Meaning you need to "reset" (create a new) StringBurrer for each iteration.
You're also missing the else where you want to preserve the correct word's order
for (int i = 0; i < newStr.length; i++) {
if (newStr[i].length() % 2 == 1) {
StringBuffer sb = new StringBuffer();
sb.append(newStr[i]);
result += sb.reverse() + " ";
}
else {
result += newStr[i] + " ";
}
}
In your method secretAgentII the StringBuffer should have no other values so that it would not be concatenated to other strings.
I placed sb.replace(0, newStr[i].length(), newStr[i]).reverse(); inside the for loop so that it would replace the existing string in every use.
I also placed an else before the line result += newStr[i] + " "; for the original string doesn't need to be concatenated when it is reversed.
static String secretAgentII(String s) {
StringBuffer sb = new StringBuffer();
String[] newStr = s.split(" ");
String result = "";
for (int i = 0; i < newStr.length; i++) {
if (newStr[i].length() % 2 != 0) {
sb.replace(0, newStr[i].length(), newStr[i]).reverse();
result += sb + " ";
} else
result += newStr[i] + " ";
}
return result;
}
Input: One Two Three Four
Output: enO owT eerhT Four
note: you are using too many spaces, try researching Java conventions on writing code.
StringBuilder + StringJoiner
Never use plain string concatenation the loop because in Java Strings are immutable. That means every s1 + s2 produces new intermediate string, which don't need (since only the end result would be used). Concatenation in the loop effects performance and increase memory allocation.
Therefore, it's highly advisable to use StringBuilder, or other built-in mechanisms like static method String.join(), StringJoiner or Collector joining() when you need to combine multiple strings together.
To avoid bother about adding a white space after each word ourself, we can make use of the StringJoiner. Through its parameterized constructor we can provide the required delimiter " ".
That's how it might be implemented:
public static String reverseOdd1(String str) {
StringJoiner result = new StringJoiner(" ");
String[] words = str.split(" ");
for (String word : words) {
if (word.length() % 2 != 0) result.add(new StringBuilder(word).reverse());
else result.add(word);
}
return result.toString();
}
Note that it's not advisable to use StringBuffer in single-threaded environment because its methods are synchronized to make it tread-safe (and synchronization doesn't come for free), and instead use it sibling StringBuilder which has the same methods.
Here's a couple of more advanced solutions.
Stream IPA - Collectors.joining()
You can generate a Stream of words, revers odd-length words using map() operation, and generate the resulting string using Collector joining().
public static String reverseOdd2(String str) {
return Arrays.stream(str.split(" "))
.map(s -> s.length() % 2 == 0 ? s : new StringBuilder(s).reverse().toString())
.collect(Collectors.joining(" "));
}
Regex - Matcher.replaceAll()
Another option is to use regular expressions.
To capture a separate word we can use the following pattern:
public static final Pattern WORD = Pattern.compile("\\b(\\w+)\\b");
Where \\b is a so-called boundary matcher denoting a word boundary (for more information, refer to the documentation).
We can create a Matcher instance using this patter and the given string and make use of the Java 9 method Matcher.replaceAll() to generate the resulting string.
public static String reverseOdd3(String str) {
return WORD.matcher(str).replaceAll(matchResult -> {
String group = matchResult.group(1);
return group.length() % 2 == 0 ? group : new StringBuilder(group).reverse().toString();
});
}
Usage Example
main
public static void main(String[] args) {
System.out.println(reverseOdd1("One Two Three Four"));
System.out.println(reverseOdd2("One Two Three Four"));
System.out.println(reverseOdd3("One Two Three Four"));
}
Output:
enO owT eerhT Four
enO owT eerhT Four
enO owT eerhT Four
Related
I am looking for code that produces the following output in standard output from the following string prepared according to a certain format.
Assumptions and rules:
Each letter is used 2 times in the given string and the letters between the same 2 letters are to be considered child letters.
The given string is always given in proper format. The string format
does not need to be checked.
Example:
Input : abccbdeeda
Expected output:
a
--b
----c
--d
----e
Explanation: since the 2 letters "b" occur between the letters "a", the letter b takes 2 hyphens (--b)
Attempt
public static void main(String[] args) {
String input = "abccbdeeda";
System.out.println("input: " + input);
String[] strSplit = input.split("");
String g = "";
String h = "-";
ArrayList<String> list = new ArrayList<String>();
int counter = 1;
boolean secondNumber;
list.add(strSplit[0]);
int dual = 0;
for (int i = 1; i < strSplit.length; i++) {
secondNumber = list.contains(strSplit[i]);
if ((secondNumber)) {
counter--;
dual = counter * 2;
for (int f = 0; f < dual; f++) {
strSplit[i] = h.concat(strSplit[i]);
}
g = "";
dual = 0;
} else {
list.add(strSplit[i]);
counter++;
}
}
Arrays.sort(strSplit);
for (int p = 0; p < strSplit.length; p++) {
System.out.println(strSplit[p]);
}
}
input: abccbdeeda
My output:
----c
----e
--b
--d
a
I wasn't able to sort the output alphabetically. How can I sort alphabetically with those hyphen characters in them?
This task is nicely done with the help of a stack. If the current character is equal to the top of the stack, then the character is closed and can be removed, otherwise we met it for the first time and it must be added to the stack and the resulting string by adding before it stack.size() * 2 dashes.
When we have completely traversed the string we can sort the resulting string.
public static void main(String[] args) {
Stack<Character> stack = new Stack<>();
String string = "abccbdeeda";
StringBuilder result = new StringBuilder();
for(int i = 0; i < string.length(); i++) {
char curChar = string.charAt(i);
if(!stack.isEmpty() && curChar == stack.peek()) {
stack.pop();
} else {
result.append("-".repeat(stack.size() * 2)).append(curChar).append(" ");
stack.add(curChar);
}
}
System.out.println(result);
System.out.println(Arrays.toString(Arrays.stream(result.toString().split(" ")).sorted().toArray()));
}
Output
a --b ----c --d ----e
[----c, ----e, --b, --d, a]
You can go through the strSplit array and extract the charactors in each element to a separate list/array. To check whether the array element contains a letter you can write a regular expression.
Ex: private final Pattern x = Pattern.compile("[a-z]");
Write a separate method to match the patern to each element in the strSplit array. This method will return the charactor in your input string.
private String findCharactor(final StringBuilder element) {
final Matcher matcher = x.matcher(element);
if (matcher.find()) {
final int matchIndex = matcher.start(); //this gives the index of the char in the string
return element.substring(matchIndex);
}
}
Add these returned charactors to a separate array and sort it using sorting function.
Suppose your result list is:
List<String> resultList = Arrays.asList("----c", "----e", "--b", "--d", "a");
You can sort it alphabetically by a single line:
Collections.sort(resultList, (o1, o2) -> new StringBuilder(o1).reverse().toString().compareTo(new StringBuilder(o2).reverse().toString()));
You can use recursion for a depth-first traversal (preorder):
public static String dfs(String string, String prefix) {
if (string.length() == 0) return "";
int i = string.indexOf(string.charAt(0), 1);
return prefix + string.charAt(0) + "\n" // current
+ dfs(string.substring(1, i), prefix + "--") // all nested
+ dfs(string.substring(i + 1), prefix); // all siblings
}
Example call:
public static void main(String[] args) {
System.out.println(dfs("abccbdeeda", ""));
}
How to reverse the words in a sentence, but not punctuation using recursion. The sentence is said to use punctuation marks: ,.?!
Input: "Jack, come home!"
Output: "home, come Jack!"
Now I have somehow managed to complete the task correctly but without using recursion.
How should I convert this work to use recursion to solve the problem?
Here's the method:
public static StringBuilder reverseSentenceWithPunctuation(String sentence, int i) {
String[] parts = sentence.split(" ");
StringBuilder newSentence = new StringBuilder();
Map<Integer, Character> punctuationMap = new HashMap<>();
for (int j = 0; j < parts.length; j++) {
if (parts[j].endsWith(",") || parts[j].endsWith(".") || parts[j].endsWith("!") || parts[j].endsWith("?")) {
char lastSymbol = parts[j].charAt(parts[j].length()-1);
punctuationMap.put(j, lastSymbol);
String changedWord = parts[j].replace(String.valueOf(lastSymbol), "");
parts[j] = changedWord;
}
}
for (int j = parts.length-1; j >= 0; j--) {
newSentence.append(parts[j]);
if (punctuationMap.containsKey(i)) {
newSentence.append(punctuationMap.get(i));
newSentence.append(" ");
} else
newSentence.append(" ");
i++;
}
return newSentence;
}
Thanks in advance!
To implement this task using recursion, a pattern matching the first and the last words followed by some delimiters should be prepared:
word1 del1 word2 del2 .... wordLast delLast
In case of matching the input the result is calculated as:
wordLast del1 REVERT(middle_part) + word1 delLast
Example implementation may be as follows (the words are considered to contain English letters and apostrophe ' for contractions):
static Pattern SENTENCE = Pattern.compile("^([A-Za-z']+)([^A-Za-z]+)?(.*)([^'A-Za-z]+)([A-Za-z']+)([^'A-Za-z]+)?$");
public static String revertSentence(String sentence) {
Matcher m = SENTENCE.matcher(sentence);
if (m.matches()) {
return m.group(5) + (m.group(2) == null ? "" : m.group(2))
+ revertSentence(m.group(3) + m.group(4)) // middle part
+ m.group(1) + (m.group(6) == null ? "" : m.group(6));
}
return sentence;
}
Tests:
System.out.println(revertSentence("Jack, come home!"));
System.out.println(revertSentence("Jack, come home please!!"));
System.out.println(revertSentence("Jane cried: Will you come home Jack, please, don't go!"));
Output:
home, come Jack!
please, home come Jack!!
go don't: please Jack home come you, Will, cried Jane!
I don't think this is a good case for a recursive function, mainly because you need 2 loops. Also, in general, iterative algorithms are better performance-wise and won't throw a stackoverflow exception.
So I think the main reasons to work with recursive functions is readability and easiness, and honestly, in this case, I think it isn't worth it.
In any case, this is my attempt to convert your code to a recursive function. As stated before, I use 2 functions because of the 2 loops. I'm sure there is a way to achieve this with a single function that first loads the map of punctuations and then compose the final String, but to be honest that would be quite ugly.
import java.util.*;
import java.util.stream.*;
public class HelloWorld{
static Character[] punctuationCharacters = {',','.','!'};
public static void main(String []args){
System.out.println(reverseSentenceWithPunctuation("Jack, come home!"));
}
private static String reverseSentenceWithPunctuation(String sentence) {
String[] parts = sentence.split(" ");
return generate(0, parts, extractPunctuationMap(0, parts));
}
private static Map<Integer, Character> extractPunctuationMap(int index, String[] parts){
Map<Integer, Character> map = new HashMap<>();
if (index >= parts.length) {
return map;
}
char lastSymbol = parts[index].charAt(parts[index].length() - 1);
if (Arrays.stream(punctuationCharacters).anyMatch(character -> character == lastSymbol)) {
parts[index] = parts[index].substring(0, parts[index].length() - 1);
map = Stream.of(new Object[][] {
{ index, lastSymbol}
}).collect(Collectors.toMap(data -> (Integer) data[0], data -> (Character) data[1]));
}
map.putAll(extractPunctuationMap(index + 1, parts));
return map;
}
private static String generate(int index, String[] parts, Map<Integer, Character> punctuationMap) {
if (index >= parts.length) {
return "";
}
String part = index == 0? " " + parts[index] : parts[index];
if (punctuationMap.containsKey(parts.length -1 - index)) {
part += punctuationMap.get(parts.length -1 - index);
}
return generate(index + 1, parts, punctuationMap) + part;
}
}
In pseudocode maybe something like that:
take the whole sentence
(a). get the first word
(b). get the last word
(if there is a punctuation after the first or last word, leave it there)
swap(a, b) and return the remaining middle of the sentence
repeat (1) and (2) until there is only two words or one
return the last two (swapped) words left (if one word, just return that)
There is a way to split a string into repeating characters using a regex function but I want to do it without using it.
for example, given a string like: "EE B" my output will be an array of strings e.g
{"EE", " ", "B"}
my approach is:
given a string I will first find the number of unique characters in a string so I know the size of the array. Then I will change the string to an array of characters. Then I will check if the next character is the same or not. if it is the same then append them together if not begin a new string.
my code so far..
String myinput = "EE B";
char[] cinput = new char[myinput.length()];
cinput = myinput.toCharArray(); //turn string to array of characters
int uniquecha = myinput.length();
for (int i = 0; i < cinput.length; i++) {
if (i != myinput.indexOf(cinput[i])) {
uniquecha--;
} //this should give me the number of unique characters
String[] returninput = new String[uniquecha];
Arrays.fill(returninput, "");
for (int i = 0; i < uniquecha; i++) {
returninput[i] = "" + myinput.charAt(i);
for (int j = 0; j < myinput.length - 1; j++) {
if (myinput.charAt(j) == myinput.charAt(j + 1)) {
returninput[j] += myinput.charAt(j + 1);
} else {
break;
}
}
} return returninput;
but there is something wrong with the second part as I cant figure out why it is not beginning a new string when the character changes.
You question says that you don't want to use regex, but I see no reason for that requirement, other than this is maybe homework. If you are open to using regex here, then there is a one line solution which splits your input string on the following pattern:
(?<=\S)(?=\s)|(?<=\s)(?=\S)
This pattern uses lookarounds to split whenever what precedes is a non whitespace character and what proceeds is a whitespace character, or vice-versa.
String input = "EE B";
String[] parts = input.split("(?<=\\S)(?=\\s)|(?<=\\s)(?=\\S)");
System.out.println(Arrays.toString(parts));
[EE, , B]
^^ a single space character in the middle
Demo
If I understood correctly, you want to split the characters in a string so that similar-consecutive characters stay together. If that's the case, here is how I would do it:
public static ArrayList<String> splitString(String str)
{
ArrayList<String> output = new ArrayList<>();
String combo = "";
//iterates through all the characters in the input
for(char c: str.toCharArray()) {
//check if the current char is equal to the last added char
if(combo.length() > 0 && c != combo.charAt(combo.length() - 1)) {
output.add(combo);
combo = "";
}
combo += c;
}
output.add(combo); //adds the last character
return output;
}
Note that instead of using an array (has a fixed size) to store the output, I used an ArrayList, which has a variable size. Also, instead of checking the next character for equality with the current one, I preferred to use the last character for that. The variable combo is used to temporarily store the characters before they go to output.
Now, here is one way to print the result following your guidelines:
public static void main(String[] args)
{
String input = "EEEE BCD DdA";
ArrayList<String> output = splitString(input);
System.out.print("[");
for(int i = 0; i < output.size(); i++) {
System.out.print("\"" + output.get(i) + "\"");
if(i != output.size()-1)
System.out.print(", ");
}
System.out.println("]");
}
The output when running the above code will be:
["EEEE", " ", "B", "C", "D", " ", "D", "d", "A"]
I have a string with several words separated by spaces, e.g. "firstword second third", and an ArrayList. I want to split the string into several pieces, and add the 'piece' strings to the ArrayList.
For example,"firstword second third" can be split to three separate strings , so the ArrayList would have 3 elements; "1 2 3 4" can be split into 4 strings, in 4 elements of the ArrayList. See the code below:
public void separateAndAdd(String notseparated) {
for(int i=0;i<canBeSepartedinto(notseparated);i++{
//what should i put here in order to split the string via spaces?
thearray.add(separatedstring);
}
}
public int canBeSeparatedinto(String string)
//what do i put here to find out the amount of spaces inside the string?
return ....
}
Please leave a comment if you dont get what I mean or I should fix some errors in this post. Thanks for your time!
You can split the String at the spaces using split():
String[] parts = inputString.split(" ");
Afterwards iterate over the array and add the individual parts (if !"".equals(parts[i]) to the list.
If you want to split on one space, you can use .split(" ");. If you want to split on all spaces in a row, use .split(" +");.
Consider the following example:
class SplitTest {
public static void main(String...args) {
String s = "This is a test"; // note two spaces between 'a' and 'test'
String[] a = s.split(" ");
String[] b = s.split(" +");
System.out.println("a: " + a.length);
for(int i = 0; i < a.length; i++) {
System.out.println("i " + a[i]);
}
System.out.println("b: " + b.length);
for(int i = 0; i < b.length; i++) {
System.out.println("i " + b[i]);
}
}
}
If you are worried about non-standard spaces, you can use "\\s+" instead of " +", as "\\s" will capture any white space, not just the 'space character'.
So your separate and add method becomes:
void separateAndAdd(String raw) {
String[] tokens = raw.split("\\s+");
theArray.ensureCapacity(theArray.size() + tokens.length); // prevent unnecessary resizes
for(String s : tokens) {
theArray.add(s);
}
}
Here's a more complete example - note that there is a small modification in the separateAndAdd method that I discovered during testing.
import java.util.*;
class SplitTest {
public static void main(String...args) {
SplitTest st = new SplitTest();
st.separateAndAdd("This is a test");
st.separateAndAdd("of the emergency");
st.separateAndAdd("");
st.separateAndAdd("broadcast system.");
System.out.println(st);
}
ArrayList<String> theArray = new ArrayList<String>();
void separateAndAdd(String raw) {
String[] tokens = raw.split("\\s+");
theArray.ensureCapacity(theArray.size() + tokens.length); // prevent unnecessary resizes
for(String s : tokens) {
if(!s.isEmpty()) theArray.add(s);
}
}
public String toString() {
StringBuilder sb = new StringBuilder();
for(String s : theArray)
sb.append(s).append(" ");
return sb.toString().trim();
}
}
I would suggest using the
apache.commons.lang.StringUtils library.
It is the easiest and covers all the different conditions you can want int he spliting up of a string with minimum code.
Here is a reference to the split method :
Split Method
you can also refer to the other options available for the split method on the same link.
Do this:
thearray = new ArrayList<String>(Arrays.asList(notseparated.split(" ")));
or if thearray already instantiated
thearray.addAll(Arrays.asList(notseparated.split(" ")));
If you want to split the string in different parts, like here i am going to show you that how i can split this string 14-03-2016 in day,month and year.
String[] parts = myDate.split("-");
day=parts[0];
month=parts[1];
year=parts[2];
You can do that using .split() try this
String[] words= inputString.split("\\s");
try this:
string to 2 part:
public String[] get(String s){
int l = s.length();
int t = l / 2;
String first = "";
String sec = "";
for(int i =0; i<l; i++){
if(i < t){
first += s.charAt(i);
}else{
sec += s.charAt(i);
}
}
String[] result = {first, sec};
return result;
}
example:
String s = "HelloWorld";
String[] res = get(s);
System.out.println(res[0]+" "+res[1])
output:
Hello World
I just want to add a space between each character of a string. Can anyone help me figuring out how to do this?
E.g. given "JAYARAM", I need "J A Y A R A M" as the result.
Unless you want to loop through the string and do it "manually" you could solve it like this:
yourString.replace("", " ").trim()
This replaces all "empty substrings" with a space, and then trims off the leading / trailing spaces.
ideone.com demonstration
An alternative solution using regular expressions:
yourString.replaceAll(".(?=.)", "$0 ")
Basically it says "Replace all characters (except the last one) with with the character itself followed by a space".
ideone.com demonstration
Documentation of...
String.replaceAll (including the $0 syntax)
The positive look ahead (i.e., the (?=.) syntax)
StringBuilder result = new StringBuilder();
for (int i = 0; i < input.length(); i++) {
if (i > 0) {
result.append(" ");
}
result.append(input.charAt(i));
}
System.out.println(result.toString());
Iterate over the characters of the String and while storing in a new array/string you can append one space before appending each character.
Something like this :
StringBuilder result = new StringBuilder();
for(int i = 0 ; i < str.length(); i++)
{
result = result.append(str.charAt(i));
if(i == str.length()-1)
break;
result = result.append(' ');
}
return (result.toString());
Blow up your String into array of chars, loop over the char array and create a new string by succeeding a char by a space.
Create a StringBuilder with the string and use one of its insert overloaded method:
StringBuilder sb = new StringBuilder("JAYARAM");
for (int i=1; i<sb.length(); i+=2)
sb.insert(i, ' ');
System.out.println(sb.toString());
The above prints:
J A Y A R A M
This would work for inserting any character any particular position in your String.
public static String insertCharacterForEveryNDistance(int distance, String original, char c){
StringBuilder sb = new StringBuilder();
char[] charArrayOfOriginal = original.toCharArray();
for(int ch = 0 ; ch < charArrayOfOriginal.length ; ch++){
if(ch % distance == 0)
sb.append(c).append(charArrayOfOriginal[ch]);
else
sb.append(charArrayOfOriginal[ch]);
}
return sb.toString();
}
Then call it like this
String result = InsertSpaces.insertCharacterForEveryNDistance(1, "5434567845678965", ' ');
System.out.println(result);
I am creating a java method for this purpose with dynamic character
public String insertSpace(String myString,int indexno,char myChar){
myString=myString.substring(0, indexno)+ myChar+myString.substring(indexno);
System.out.println(myString);
return myString;
}
This is the same problem as joining together an array with commas. This version correctly produces spaces only between characters, and avoids an unnecessary branch within the loop:
String input = "Hello";
StringBuilder result = new StringBuilder();
if (input.length() > 0) {
result.append(input.charAt(0));
for (int i = 1; i < input.length(); i++) {
result.append(" ");
result.append(input.charAt(i));
}
}
public static void main(String[] args) {
String name = "Harendra";
System.out.println(String.valueOf(name).replaceAll(".(?!$)", "$0 "));
System.out.println(String.valueOf(name).replaceAll(".", "$0 "));
}
This gives output as following use any of the above:
H a r e n d r a
H a r e n d r a
One can use streams with java 8:
String input = "JAYARAM";
input.toString().chars()
.mapToObj(c -> (char) c + " ")
.collect(Collectors.joining())
.trim();
// result: J A Y A R A M
A simple way can be to split the string on each character and join the parts using space as the delimiter.
Demo:
public class Main {
public static void main(String[] args) {
String s = "JAYARAM";
s = String.join(" ", s.split(""));
System.out.println(s);
}
}
Output:
J A Y A R A M
ONLINE DEMO
Create a char array from your string
Loop through the array, adding a space +" " after each item in the array(except the last one, maybe)
BOOM...done!!
If you use a stringbuilder, it would be efficient to initalize the length when you create the object. Length is going to be 2*lengthofString-1.
Or creating a char array and converting it back to the string would yield the same result.
Aand when you write some code please be sure that you write a few test cases as well, it will make your solution complete.
I believe what he was looking for was mime code carrier return type code such as %0D%0A (for a Return or line break)
and
\u00A0 (for spacing)
or alternatively
$#032