Codingbat plusOut - StringBuffer Trouble - java

Given a string and a non-empty word string, return a version of the original String where all chars have been replaced by pluses ("+"), except for appearances of the word string which are preserved unchanged.
plusOut("12xy34", "xy") → "++xy++"
plusOut("12xy34", "1") → "1+++++"
plusOut("12xy34xyabcxy", "xy") → "++xy++xy+++xy"
I am having trouble trying to code a StringBuffer solution to this problem.
This is the original code to this:
public static String plusOut(String str, String word) {
int i = 0;
String str2 = "";
while (i < str.length() - word.length()+1)
if (!str.substring(i,i+word.length()).equals(word)) {
str2 += "+";
i++;
}
else {
str2 += word;
i += word.length(); //found pattern - skip
}
//if any remaining chars at end (guaranteed not to be pattern) replace
//with +s
if (i < str.length() && !str.substring(i).equals(word.substring(1))) {
for (int j = 0; j < word.length()-1; j++) str2 += "+";
}
return str2;
}

public String plusOut(String str, String word) {
String result = "";
int i = 0 ;
while(i < str.length() ) {
if (str.substring(i).startsWith(word)) {
result = result + word;
i = i + word.length();
} else {
result = result + "+" ;
i++;
}
}
return result ;
}
//StringBuilder
public String plusOut(String str, String word) {
StringBuilder strBuilder = new StringBuilder();
int i = 0 ;
while(i < str.length() ) {
if (str.substring(i).startsWith(word)) {
strBuilder.append(word);
i = i + word.length();
} else {
strBuilder.append("+");
i++;
}
}
return strBuilder.toString();
}

Here's what I came up with:
public String plusOut(String str, String word)
{
//Create a blank string.
String out = "";
//Create a counter to get the end amount.
int endAmt = 0;
//We can only manipulate from 0 to str.length() - word.length() in this for loop, because
//when searching for word in str, we can't go beyond the bounds.
for (int i = 0; i < str.length() - word.length(); i++)
{
//If we find word in str,
if (str.substring(i, i + word.length()).equals(word))
{
//We append word and increment 2 times further.
out = out + str.substring(i, i + word.length());
//increment i by 2 (one here, and one at the end)
i += word.length() - 1;
//We set the endAmt equal to the next iteration for future use when getting the rest
//of the amount later.
endAmt = i + 1;
}
//if it doesn't match, we change the character to a '+'
else
{
out = out.substring(0,i) + '+';
}
}
//Now, we finish the string after the searching for word in str.
//If the last substring is word, we add word to the mix.
if (str.substring(str.length() - word.length()).equals(word))
{
out = out + word;
}
//If it's not, then we refactor the string to after then last instance of word
else
{
out = out.substring(0, endAmt);
//and then we add the remaining amount of +'s
for (int i = 0; i < str.length() - endAmt; i++)
{
out = out + "+";
}
}
//finally, we return the string.
return out;
}

Here's a very simplified and easy to understand code
public static String plusOut(String str,String word){
StringBuffer b = new StringBuffer();
int indexOfWord = str.indexOf(word, 0);
for (int i = 0; i < str.length(); i++) {
if(i==indexOfWord){
b.append(word);
i=i+word.length()-1;//move index by word length
//get next index for the word
indexOfWord = str.indexOf(word,indexOfWord+word.length());
}else{
b.append("+");
}
}
return b.toString();
}

public String plusOut(String str, String word) {
String temp = str.replace(word, "+");
String newStr = "";
for (int i=0; i<temp.length(); i++)
{
if (temp.charAt(i) == '+')
{
newStr += word;
}
else
{
newStr += "+";
}
}
return newStr;
}

public String plusOut(String str, String word) {
String result = "";
for (int i = 0; i < str.length(); i++){
if (str.substring(i).length() >= word.length()
&& str.substring(i, i + word.length()).equals(word)) {
result += word;
i += word.length() - 1;
}
else if (str.length() < word.length()
|| str.substring(i).length() < word.length())
result += '+';
else
result += '+';
}
return result;
}

public String plusOut(String str, String word) {
String newStr = "";
int sLength = str.length();
int wLength = word.length();
for (int i = 0; i < sLength; i++){
if (i <= (sLength-wLength) && str.substring(i, i+wLength).equals(word)){
newStr += word;
i += (wLength-1);
continue;
}
newStr += "+";
}
return newStr;
}

Solution with regular expression:
public String plusOut(String str, String word) {
String regex = "(?<!(?=word).{0,M}).";
return str.replaceAll(
regex
.replace("word", java.util.regex.Pattern.quote(word))
.replace("M", String.valueOf(word.length() - 1)), "+");
}
Explanation:
Negative Lookbehind (?<!(?=word).{0,M}) - Assert that the Regex below does not match
Positive Lookahead (?=word) - Assert that the Regex below matches
Word matches the characters word literally (case sensitive)
. matches any character (except for line terminators)
{0,M} matches the characters {0,M} literally (case sensitive)
. matches any character (except for line terminators)

Related

Replacing the number with the number of spaces

I have a String:
String example = "AA5DD2EE3MM";
I want to replace the number with the number of spaces. Example:
String example = "AA DD EE MM"
If the String would be
String anotherExample = "a3ee"
It should turn into:
String anotherExample = "a ee"
I want to do it for any string. Not only for the examples above.
Split your input at digit and non digit chars as a stream, map digits to the corsponding number of spaces using String.repeat, collect to string using Collectors.joining():
String input = "AA5DD2EE3MM";
String regex = "(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)";
String result = Pattern.compile(regex)
.splitAsStream(input)
.map(s -> s.matches("\\d+") ? " ".repeat(Integer.parseInt(s)) : s)
.collect(Collectors.joining());
You could also use this approach, which is simpler but also far less elegant:
String example = "a4aa";
String newString = "";
for (int i = 0; i < example.length(); i++) {
if (Character.isDigit(example.charAt(i))) {
for (int a = 0; a < Character.getNumericValue(example.charAt(i)); a++) {
newString += " ";
}
} else {
newString += example.charAt(i);
}
}
System.out.println(newString);
Using a pattern matcher approach:
String input = "AA5DD2EE3MM";
Pattern pattern = Pattern.compile("\\d+");
Matcher m = pattern.matcher(input);
StringBuffer buffer = new StringBuffer();
while (m.find()) {
m.appendReplacement(buffer,new String(new char[Integer.valueOf(m.group())]).replace("\0", " "));
}
m.appendTail(buffer);
System.out.println(buffer.toString()); // AA DD EE MM
The idea here is to iterate the string, pausing at each digit match. We replace each digit with space replicated the same number of times as the digit.
public static String replaceDigitsWithSpaces(String input) {
String result = "";
int len = input.length(), i =0;
while( i < len) {
if(Character.isLetter(input.charAt(i))) {
result += input.charAt(i);
}else if(Character.isDigit(input.charAt(i))) {
//generate number upto characters
int k = 0, j = i;
String temp = "";
while(j < len) {
if(Character.isDigit(input.charAt(j))) {
temp += input.charAt(j);
j++;
}else {
break;
}
}
k = Integer.parseInt(temp);
while(k != 0) {
result+= " ";
k--;
}
i = j;
continue;
}
i++;
}
return result;
}
input:: "AA23BB1C11C8"<br>
output:: AA BB C C .
StringBuilder is more efficient for concatenation:
public static String spaceIt(String s) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (Character.isDigit(c)) {
for (int j = 0; j < Character.digit(c, 10); j++) {
sb.append(' ');
}
} else {
sb.append(c);
}
}
return sb.toString();
}

CodingBat starOut, why using substring won't work correctly

I am solving coding challenge on CodingBat.com. Here is the question:
Given a string and a non-empty word string, return a version of the
original String where all chars have been replaced by pluses ("+"),
except for appearances of the word string which are preserved
unchanged.
plusOut("12xy34", "xy") → "++xy++"
plusOut("12xy34", "1") → "1+++++"
plusOut("12xy34xyabcxy", "xy") → "++xy++xy+++xy"
Here is my attempted solution:
public String plusOut(String str, String word)
{
String ret = "";
for (int i = 0; i < str.length() - word.length() + 1; ++i) {
if (str.substring(i, i + word.length()).equals(word))
ret += word;
else
ret += "+";
}
return ret;
}
But is giving wrong outputs: giving too many plus signs. I don't understand why this shouldn't work. I suspect that the substring method is not returning enough matches, so the plus sign is appended. But I don't see why this maybe so.
I would use a StringBuilder to construct the result to avoid creating multiple String objects as String in java is immutable:
public String plusOut(String str, String word) {
StringBuilder result = new StringBuilder(str);
int len = str.length(), wordLen = word.length(), index = 0;
while(index < len){
if ( (index <= len-wordLen) && (str.substring(index, index+wordLen).equals(word))){
index += wordLen;
continue;
}
result.setCharAt(index++, '+');
}
return result.toString();
}
You were doing a few things wrong. I've corrected your code although there is probably a cleaner way to do this. I will explain what's changed below.
public static String plusOut(String str, String word)
{
String ret = "";
for (int i = 0; i < str.length(); ++i) {
int endIndex = i + word.length();
if (endIndex < str.length() + 1
&& str.substring(i, i + word.length()).equals(word)) {
ret += word;
i = i + word.length() - 1;
} else
ret += "+";
}
return ret;
}
First mistake is that you are not looping over the whole content of str and therefore never reach the last character of str.
Another problem is that once you find a word, you don't "jump" to the correct next index in the loop, but still continue looping over characters of the found word, which results in additional + characters in your result string.
i = i + word.length() - 1;
In your solution, the above will put you to the next index of a character inside str that you should be looking at. Example:
In string 12xy34xyabcxy looking for xy.
You will find that word xy starts at index 2 and ends at 3.
At that point you have result string ++xy after adding the found word to it.
Now, the problem begins. You still end up going over index 3 and adding an additional + because the next couple of characters do not add up to your word.
The 2 characters after the found xy also add + and you now have ++xy+++ which is incorrect.
endIndex < str.length() + 1
endIndex is named after what it is - end index of your substring.
This check prevents us from checking for xy when there aren't enough characters left in the string from current index to the last in order to make up xy, so we end up adding + for each remaining character instead.
Do it like this :
public static String plusOut(String str, String word)
{
String ret = "";
int i;
for (i = 0; i < str.length() - word.length() +1 ; i++) {
if (str.substring(i, i + word.length()).equals(word)) {
ret += word;
i += word.length() - 1;
}
else
ret += "+";
}
while (i < str.length()) {
ret += "+";
i++;
}
return ret;
}
Here is your solution
public String plusOut(String str, String word)
{
String ret = "";
for (int i = 0; i < str.length();) {
if (i + word.length()<= str.length() && str.substring(i, i + word.length()).equals(word)) {
ret += word;
i+=word.length();
}
else{
ret += "+";
i++;
}
}
return ret;
}

How to return string with all instances of a string replaced by another string ( Java )

In this program, I am trying to return a new string that is composed of new letters that were added and old letters if the didn't fit the constraints. I am stuck in terms of I don't know how to fix my code so that it prints correctly. Any help or suggestions is greatly appreciated!
Here are some examples:
str: "asdfdsdfjsdf", word: "sdf", c: "q"
should return "aqdqjq", I'm getting "asdqqq"
str: "aaaaaaaa", word: "aaa", c: "w"
should return "wwaa", as of right now my code only returns "ww"
public static String replaceWordWithLetter(String str, String word, String c)
String result = "";
int index = 0;
while (index < str.length() )
{
String x = str.substring(index, index + word.length() );
if (x.equals(word))
{
x = c;
index = index + word.length();
}
result = result + x;
index++;
}
if (str.length() > index)
{
result = result + str.substring(index, str.length() - index);
}
return result;
}
You seem to be overcomplicating this. You can simply use the replace() method:
public static String replaceWordWithLetter(String str, String word, String c) {
return str.replace(word, c);
}
Which when called as:
replaceWordWithLetter("asdfdsdfjsdf", "sdf", "q")
Produces the output:
aqdqjq
The problem with your current method is that if the substring is not equal to word, then you will append as many characters as there are in word, and then only move up one index. If you will not be replacing the sequence, then you only need to append one character to result. Also it is much more efficient to use a StringBuilder. Also as noted if the String is not divisible by word.length(), this will throw a StringIndexOutOfBoundsError. To solve this you can use the Math.min() method to ensure that the substring does not go out of bounds. Original method with fixes:
public static String replaceWordWithLetter(String str, String word, String c) {
StringBuilder result = new StringBuilder();
int index = 0;
while (index < str.length() )
{
String x = str.substring(index, Math.min(index + word.length(), str.length()));
if (x.equals(word))
{
result.append(c);
index = index + word.length();
}
//If we aren't replacing, only add one char
else {
result.append(x.charAt(0));
index++;
}
}
if (str.length() > index)
{
result.append(str.substring(index, str.length() - index));
}
return result.toString();
}
Found the fix to my issue using #GBlodgett's code:
String result = "";
int index = 0;
while (index <= str.length() - word.length() )
{
String x = str.substring(index, index + word.length() );
if (x.equals(word))
{
result = result + c;
index = index + word.length();
}
else {
result = result + x.charAt(0);
index++;
}
}
if (str.length() < index + word.length())
{
result = result + (str.substring(index));
}
return result;
}
You can use String.replaceAll() method.
example:
public class StringReplace {
public static void main(String[] args) {
String str = "aaaaaaaa";
String fnd = "aaa";
String rep = "w";
System.out.println(str.replaceAll(fnd, rep));
System.out.println("asdfdsdfjsdf".replaceAll("sdf", "q"));
}
}
Output:
wwaa
aqdqjq

plusOut code java

I'm trying to write a code that will give this output:
plusOut("12xy34", "xy") → "++xy++"
it returns a string where the characters in the original have been replaced by + except for where the 2nd string appears in the first string, but im having problems with my code. Here it is:
public String plusOut(String str, String word) {
String newString = "";
for (int i=0; i<str.length()-1; i++) {
if (str.substring(i, word.length()).equals(word)) {
newString = newString + str.substring(i, word.length());
}
else {
newString = newString + "+";
}
}
return newString;
}
There are some bugs in your code, see the comments.
public String plusOut(String str, String word) {
String newString = "";
// iterate up to length() to catch the last char if word.length() is 1
for (int i = 0; i < str.length(); i++) {
// use min() to avoid an IndexOutOfRange
String sub = str.substring(i, Math.min(i+word.length(), str.length()));
if (sub.equals(word)) {
newString = newString + sub;
// skip remaining characters of word
i += sub.length()-1;
}
else {
newString = newString + "+";
}
}
return newString;
}
In addition to that, I'd use a StringBuilder instead of the + operator.
You should really tell us what specific problems you are facing with your current code. In any case, here's how I would do it:
Split str on all occurrences of word to form a String[].
Loop through this array and append a number of '+' characters to newString corresponding to the length of whatever element of the array you're on.
On the same loop iteration, append word to newString, unless of course you're on the last element of the array.
This is what I mean:
public static String plusOut(String str, String word) {
StringBuilder newString = new StringBuilder(str.length());
String[] split = str.split(word);
for (int i = 0; i < split.length; i++) {
for (int j = 0; j < split[i].length(); j++)
newString.append('+');
if (i != split.length - 1)
newString.append(word);
}
return newString.toString();
}
Oh and just another tip: try to avoid appending to strings repeatedly within a loop. If you need to, use a StringBuilder instead.
System.out.println(plusOut("12xy34", "xy"));
++xy++
The best and simplest way I can think of is to use regular expressions and do a replaceAll.
General idea will be to get the second character build an regex with that and replaceAll with the regular expression and the replacement character.
public String plusOut(String str, String word) {
String regEx="[^"+Pattern.quote(word)+"]";
str.replaceAll(regEx,"+");
}
Note that the Pattern.quote() will make sure that your word won't screw the regex.
I didn't try out the code, but it should work without a problem.
This will do that for you.
public String plusOut(String str, String word) {
if(!str.contains(word)){
System.out.println("Word not found in string!");
return "Ut-oh!";
}
int indexOfStart = str.indexOf(word);
StringBuilder sb = new StringBuilder();
for(int i = 0; i<indexOfStart; i++){
sb.append('+');
}
sb.append(word);
for(int i=indexOfStart+word.length(); i < str.length(); i++){
sb.append('+');
}
return sb.toString();
}
So many answers! Well, here's mine as well:
public static String plusOut(String str, String word) {
String output = "";
int index = str.indexOf(word); // if -1 is returned, replace all chars
for (int i= 0; i < str.length(); i++) {
if(i == index)
{
output += word;
i += word.length() -1; // because i++ will still occurr
continue;
}
output += "+";
}
return output;
}
and test code in main:
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
String test = "somethinghello12345.1!#";
System.out.println(test + " -> " + plusOut(test, "hello"));
test = "somethinghello12345.1!#";
System.out.println(test + " -> " + plusOut(test, "not gonna work"));
}
will produce the ouput:
somethinghello12345.1!# -> +++++++++hello+++++++++
somethinghello12345.1!# -> +++++++++++++++++++++++
Try this :
public static String plusOut(String word, String find) {
StringBuilder newStr = new StringBuilder();
int start = word.indexOf(find);
if (start > -1) {
for (int i = 0; i < start; i++) {
newStr.append("+");
}
newStr.append(find);
for (int i = 0; i < word.length() - (start + find.length()); i++) {
newStr.append("+");
}
}
return newStr;
}

Write a method to replace all spaces in a string with '%20'

I have a question about a programming problem from the book Cracking The Code Interview by Gayl Laakmann McDowell, 5th Edition.
The problem states: Write a method to replace all spaces in a string with '%20'. Assume string has sufficient space at end of string to hold additional characters, and that you're given a true length of a string. I used the books code, implementing the solution in Java using a character array (given the fact that Java Strings are immutable):
public class Test {
public void replaceSpaces(char[] str, int length) {
int spaceCount = 0, newLength = 0, i = 0;
for(i = 0; i < length; i++) {
if (str[i] == ' ')
spaceCount++;
}
newLength = length + (spaceCount * 2);
str[newLength] = '\0';
for(i = length - 1; i >= 0; i--) {
if (str[i] == ' ') {
str[newLength - 1] = '0';
str[newLength - 2] = '2';
str[newLength - 3] = '%';
newLength = newLength - 3;
}
else {
str[newLength - 1] = str[i];
newLength = newLength - 1;
}
}
System.out.println(str);
}
public static void main(String[] args) {
Test tst = new Test();
char[] ch = {'t', 'h', 'e', ' ', 'd', 'o', 'g', ' ', ' ', ' ', ' ', ' ', ' '};
int length = 6;
tst.replaceSpaces(ch, length);
}
}
The output I am getting from the replaceSpaces() call is: the%20do which is cutting of the last character of the original array. I have been scratching my head over this, can anyone explain to me why the algorithm is doing this?
public String replace(String str) {
String[] words = str.split(" ");
StringBuilder sentence = new StringBuilder(words[0]);
for (int i = 1; i < words.length; ++i) {
sentence.append("%20");
sentence.append(words[i]);
}
return sentence.toString();
}
You are passing the length as 6, which is causing this. Pass length as 7 including space.
Other wise
for(i = length - 1; i >= 0; i--) {
will not consider last char.
With these two changes I got the output: the%20dog
1) Change space count to 2 [since length already includes 1 of the 3 characters you need for %20]
newLength = length + (spaceCount * 2);
2) Loop should start on length
for(i = length; i >= 0; i--) {
Here is my solution. I check for the ascii code 32 then put a %20 instead of it.Time complexity of this solution is O(N)
public String replace(String s) {
char arr[] = s.toCharArray();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < arr.length; i++) {
if (arr[i] == 32)
sb.append("%20");
else
sb.append(arr[i]);
}
return sb.toString();
}
This is my code for this question. Seems like working for me. If you're interested, please have a look. It's written in JAVA
public class ReplaceSpaceInString {
private static char[] replaceSpaceInString(char[] str, int length) {
int spaceCounter = 0;
//First lets calculate number of spaces
for (int i = 0; i < length; i++) {
if (str[i] == ' ')
spaceCounter++;
}
//calculate new size
int newLength = length + 2*spaceCounter;
char[] newArray = new char[newLength+1];
newArray[newLength] = '\0';
int newArrayPosition = 0;
for (int i = 0; i < length; i++) {
if (str[i] == ' ') {
newArray[newArrayPosition] = '%';
newArray[newArrayPosition+1] = '2';
newArray[newArrayPosition+2] = '0';
newArrayPosition = newArrayPosition + 3;
}
else {
newArray[newArrayPosition] = str[i];
newArrayPosition++;
}
}
return newArray;
}
public static void main(String[] args) {
char[] array = {'a','b','c','d',' ','e','f','g',' ','h',' ','j'};
System.out.println(replaceSpaceInString(array, array.length));
}
}
You can also use substring method and the ascii for space (32).
public String replaceSpaceInString(String s){
int i;
for (i=0;i<s.length();i++){
System.out.println("i is "+i);
if (s.charAt(i)==(int)32){
s=s.substring(0, i)+"%20"+s.substring(i+1, s.length());
i=i+2;
}
}
return s;
}
To test:
System.out.println(cc.replaceSpaceInString("mon day "));
Output:
mon%20day%20
You could just do this.
No need to calculate the length or whatever.
Strings are immutable anyways.
import java.util.*;
public class ReplaceString {
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
String str=in.nextLine();
String n="";
for(int i=0;i<str.length();i++)
{
if(str.charAt(i)==' ')
n=n+"%20";
else
n=n+str.charAt(i);
}
str=n;
System.out.println(str);
}
}
void Rep_Str(char *str)
{
int j=0,count=0;
int stlen = strlen(str);
for (j = 0; j < stlen; j++)
{
if (str[j]==' ')
{
count++;
}
}
int newlength = stlen+(count*2);
str[newlength--]='\0';
for (j = stlen-1; j >=0 ; j--)
{
if (str[j]==' ')
{
str[newlength--]='0';
str[newlength--]='2';
str[newlength--]='%';
}
else
{
str[newlength--]=str[j];
}
}
}
This code works :)
We can use a regular expression to solve this problem. For example:
public String replaceStringWithSpace(String str){
return str.replaceAll("[\\s]", "%20");
}
This works correctly. However, using a StringBuffer object increases space complexity.
Scanner scn = new Scanner(System.in);
String str = scn.nextLine();
StringBuffer sb = new StringBuffer(str.trim());
for(int i = 0;i<sb.length();i++){
if(32 == (int)sb.charAt(i)){
sb.replace(i,i+1, "%20");
}
}
public static String replaceAllSpaces(String s) {
char[] c = s.toCharArray();
int spaceCount = 0;
int trueLen = s.length();
int index = 0;
for (int i = 0; i < trueLen; i++) {
if (c[i] == ' ') {
spaceCount++;
}
}
index = trueLen + spaceCount * 2;
char[] n = new char[index];
for (int i = trueLen - 1; i >= 0; i--) {
if (c[i] == ' ') {
n[index - 1] = '0';
n[index - 2] = '2';
n[index - 3] = '%';
index = index - 3;
} else {
n[index - 1] = c[i];
index--;
}
}
String x = new String(n);
return x;
}
Another way of doing this.
I am assuming the trailing spaces don't need to be converted to %20 and that the trailing spaces provide enough room for %20s to be stuffed in between
public class Main {
public static void main(String[] args) {
String str = "a sd fghj ";
System.out.println(replacement(str));//a%20sd%20fghj
}
private static String replacement(String str) {
char[] chars = str.toCharArray();
int posOfLastChar = 0;
for (int i = 0; i < chars.length; i++) {
if (chars[i] != ' ') {
posOfLastChar = i;
}
}
int newCharPosition = chars.length - 1;
//Start moving the characters to th end of the array. Replace spaces by %20
for (int i = posOfLastChar; i >= 0; i--) {
if (chars[i] == ' ') {
chars[newCharPosition] = '0';
chars[--newCharPosition] = '2';
chars[--newCharPosition] = '%';
} else {
chars[newCharPosition] = chars[i];
}
newCharPosition--;
}
return String.valueOf(chars);
}
}
public class ReplaceChar{
public static void main(String []args){
String s = "ab c de ";
System.out.println(replaceChar(s));
}
public static String replaceChar(String s){
boolean found = false;
StringBuilder res = new StringBuilder(50);
String str = rev(s);
for(int i = 0; i <str.length(); i++){
if (str.charAt(i) != ' ') { found = true; }
if (str.charAt(i) == ' '&& found == true) { res.append("%02"); }
else{ res.append(str.charAt(i)); }
}
return rev(res.toString());
}
// Function to reverse a string
public static String rev(String s){
StringBuilder result = new StringBuilder(50);
for(int i = s.length()-1; i>=0; i-- ){
result.append(s.charAt(i));
}
return result.toString();
}}
A simple approach:
Reverse the given string and check where the first character appears.
Using string builder to append "02%" for spaces - since the string is reversed.
Finally reverse the string once again.
Note: We reverse the string so as to prevent an addition of "%20" to the trailing spaces.
Hope that helps!
The question in the book mentions that the replacement should be in place so it is not possible to assign extra arrays, it should use constant space. You should also take into account many edge cases, this is my solution:
public class ReplaceSpaces {
public static void main(String[] args) {
if ( args.length == 0 ) {
throw new IllegalArgumentException("No string");
}
String s = args[0];
char[] characters = s.toCharArray();
replaceSpaces(characters);
System.out.println(characters);
}
static void replaceSpaces(char[] s) {
int i = s.length-1;
//Skipping all spaces in the end until setting `i` to non-space character
while( i >= 0 && s[i] == ' ' ) { i--; }
/* Used later to check there is enough extra space in the end */
int extraSpaceLength = s.length - i - 1;
/*
Used when moving the words right,
instead of finding the first non-space character again
*/
int lastNonSpaceCharacter = i;
/*
Hold the number of spaces in the actual string boundaries
*/
int numSpaces = 0;
/*
Counting num spaces beside the extra spaces
*/
while( i >= 0 ) {
if ( s[i] == ' ' ) { numSpaces++; }
i--;
}
if ( numSpaces == 0 ) {
return;
}
/*
Throw exception if there is not enough space
*/
if ( extraSpaceLength < numSpaces*2 ) {
throw new IllegalArgumentException("Not enough extra space");
}
/*
Now we need to move each word right in order to have space for the
ascii representation
*/
int wordEnd = lastNonSpaceCharacter;
int wordsCounter = 0;
int j = wordEnd - 1;
while( j >= 0 ) {
if ( s[j] == ' ' ){
moveWordRight(s, j+1, wordEnd, (numSpaces-wordsCounter)*2);
wordsCounter++;
wordEnd = j;
}
j--;
}
replaceSpacesWithAscii(s, lastNonSpaceCharacter + numSpaces * 2);
}
/*
Replaces each 3 sequential spaces with %20
char[] s - original character array
int maxIndex - used to tell the method what is the last index it should
try to replace, after that is is all extra spaces not required
*/
static void replaceSpacesWithAscii(char[] s, int maxIndex) {
int i = 0;
while ( i <= maxIndex ) {
if ( s[i] == ' ' ) {
s[i] = '%';
s[i+1] = '2';
s[i+2] = '0';
i+=2;
}
i++;
}
}
/*
Move each word in the characters array by x moves
char[] s - original character array
int startIndex - word first character index
int endIndex - word last character index
int moves - number of moves to the right
*/
static void moveWordRight(char[] s, int startIndex, int endIndex, int moves) {
for(int i=endIndex; i>=startIndex; i--) {
s[i+moves] = s[i];
s[i] = ' ';
}
}
}
Any reason not to use 'replace' method?
public String replaceSpaces(String s){
return s.replace(" ", "%20");}
Hm... I am wondering about this problem as well. Considering what I have seen in here. The book solution does not fit Java because it uses in-place
char []
modification and solutions in here that use char [] or return void don't fit as well because Java does not use pointers.
So I was thinking, the obvious solution would be
private static String encodeSpace(String string) {
return string.replcaceAll(" ", "%20");
}
but this is probably not what your interviewer would like to see :)
// make a function that actually does something
private static String encodeSpace(String string) {
//create a new String
String result = new String();
// replacement
final String encodeSpace = "%20";
for(char c : string.toCharArray()) {
if(c == ' ') result+=encodeString;
else result+=c;
}
return result;
}
this looks fine I thought, and you only need one pass through the string, so the complexity should be O(n), right? Wrong! The problem is in
result += c;
which is the same as
result = result + c;
which actually copies a string and creates a copy of it. In java strings are represented as
private final char value[];
which makes them immutable (for more info I would check java.lang.String and how it works). This fact will bump up the complexity of this algorithm to O(N^2) and a sneaky recruiter can use this fact to fail you :P Thus, I came in with a new low-level solution which you will never use in practice, but which is good in theory :)
private static String encodeSpace(String string) {
final char [] original = string != null? string.toCharArray() : new char[0];
// ASCII encoding
final char mod = 37, two = 50, zero = 48, space = 32;
int spaces = 0, index = 0;
// count spaces
for(char c : original) if(c == space) ++spaces;
// if no spaces - we are done
if(spaces == 0) return string;
// make a new char array (each space now takes +2 spots)
char [] result = new char[string.length()+(2*spaces)];
for(char c : original) {
if(c == space) {
result[index] = mod;
result[++index] = two;
result[++index] = zero;
}
else result[index] = c;
++index;
}
return new String(result);
}
But I wonder what is wrong with following code:
private static String urlify(String originalString) {
String newString = "";
if (originalString.contains(" ")) {
newString = originalString.replace(" ", "%20");
}
return newString;
}
Question : Urlify the spaces with %20
Solution 1 :
public class Solution9 {
public static void main(String[] args) {
String a = "Gini Gina Protijayi";
System.out.println( urlencode(a));
}//main
public static String urlencode(String str) {
str = str.trim();
System.out.println("trim =>" + str);
if (!str.contains(" ")) {
return str;
}
char[] ca = str.toCharArray();
int spaces = 0;
for (char c : ca) {
if (c == ' ') {
spaces++;
}
}
char[] newca = new char[ca.length + 2 * spaces];
// a pointer x has been added
for (int i = 0, x = 0; i < ca.length; i++) {
char c = ca[i];
if (c == ' ') {
newca[x] = '%';
newca[x + 1] = '2';
newca[x + 2] = '0';
x += 3;
} else {
newca[x] = c;
x++;
}
}
return new String(newca);
}
}//urlify
My solution using StringBuilder with time complexity O(n)
public static String url(String string, int length) {
char[] arrays = string.toCharArray();
StringBuilder builder = new StringBuilder(length);
for (int i = 0; i < length; i++) {
if (arrays[i] == ' ') {
builder.append("%20");
} else {
builder.append(arrays[i]);
}
}
return builder.toString();
}
Test case :
#Test
public void testUrl() {
assertEquals("Mr%20John%20Smith", URLify.url("Mr John Smith ", 13));
}
Can you use StringBuilder?
public String replaceSpace(String s)
{
StringBuilder answer = new StringBuilder();
for(int i = 0; i<s.length(); i++)
{
if(s.CharAt(i) == ' ')
{
answer.append("%20");
}
else
{
answer.append(s.CharAt(i));
}
}
return answer.toString();
}
I am also looking at that question in the book. I believe we can just use String.trim() and String.replaceAll(" ", "%20) here
I updated the solution here. http://rextester.com/CWAPCV11970
If we are creating new array and not in-place trasition, then why do we need to walk backwards?
I modified the real solution slightly to walk forward to create target Url-encoded-string.
Time complexity:
O(n) - Walking original string
O(1) - Creating target string incrementally
where 'n' is number of chars in original string
Space complexity:
O(n + m) - Duplicate space to store escaped spaces and string.
where 'n' is number of chars in original string and 'm' is length of escaped spaces
public static string ReplaceAll(string originalString, char findWhat, string replaceWith)
{
var newString = string.Empty;
foreach(var character in originalString)
newString += findWhat == character? replaceWith : character + string.Empty;
return newString;
}
class Program
{
static void Main(string[] args)
{
string name = "Stack Over Flow ";
StringBuilder stringBuilder = new StringBuilder();
char[] array = name.ToCharArray(); ;
for(int i = 0; i < name.Length; i++)
{
if (array[i] == ' ')
{
stringBuilder.Append("%20");
}
else
stringBuilder.Append(array[i]);
}
Console.WriteLine(stringBuilder);
Console.ReadLine();
}
}
public class Sol {
public static void main(String[] args) {
String[] str = "Write a method to replace all spaces in a string with".split(" ");
StringBuffer sb = new StringBuffer();
int count = 0;
for(String s : str){
sb.append(s);
if(str.length-1 != count)
sb.append("%20");
++count;
}
System.out.println(sb.toString());
}
}
public class Test {
public static void replace(String str) {
String[] words = str.split(" ");
StringBuilder sentence = new StringBuilder(words[0]);
for (int i = 1; i < words.length; i++) {
sentence.append("%20");
sentence.append(words[i]);
}
sentence.append("%20");
System.out.println(sentence.toString());
}
public static void main(String[] args) {
replace("Hello World "); **<- Hello<3spaces>World<1space>**
}
}
O/P:: Hello%20%20%20World%20
Remember that you only to want replace ' ' with '%20' when the latter is not a leading or trailing space. Several answers above do not account for this. For what it's worth, I get "index out of bounds error" when I run Laakmann's solution example.
Here's my own solution, which runs O(n) and is implemented in C#:
public static string URLreplace(string str, int n)
{
var len = str.Length;
if (len == n)
return str;
var sb = new StringBuilder();
var i = 0;
while (i < len)
{
char c = str[i];
if (c == ' ')
{
while (i < len && str[i] == ' ')
{
i++; //skip ahead
}
}
else
{
if (sb.Length > 0 && str[i - 1] == ' ')
sb.Append("%20" + c);
else
sb.Append(c);
i++;
}
}
return sb.ToString();
}
Test:
//Arrange
private string _str = " Mr John Smith ";
private string _result = "Mr%20John%20Smith";
private int _int = 13;
[TestMethod]
public void URLified()
{
//Act
var cleaned = URLify.URLreplace(_str, _int);
//Assert
Assert.IsTrue(cleaned == _result);
}
One line code
System.out.println(s.trim().replace(" ","%20"));
// while passing the input make sure you use the .toCharArray method becuase strings are immutable
public static void replaceSpaces(char[] str, int length) {
int spaceCount = 0, newLength = 0, i = 0;
for (i = 0; i < length; i++) {
if (str[i] == ' ')
spaceCount++;
}
newLength = length + (spaceCount * 2);
// str[newLength] = '\0';
for (i = length - 1; i >= 0; i--) {
if (str[i] == ' ') {
str[newLength - 1] = '0';
str[newLength - 2] = '2';
str[newLength - 3] = '%';
newLength = newLength - 3;
} else {
str[newLength - 1] = str[i];
newLength = newLength - 1;
}
}
System.out.println(str);
}
public static void main(String[] args) {
// Test tst = new Test();
char[] ch = "Mr John Smith ".toCharArray();
int length = 13;
replaceSpaces(ch, length);
}
`// Maximum length of string after modifications.
const int MAX = 1000;
// Replaces spaces with %20 in-place and returns
// new length of modified string. It returns -1
// if modified string cannot be stored in str[]
int replaceSpaces(char str[])
{
// count spaces and find current length
int space_count = 0, i;
for (i = 0; str[i]; i++)
if (str[i] == ' ')
space_count++;
// Remove trailing spaces
while (str[i-1] == ' ')
{
space_count--;
i--;
}
// Find new length.
int new_length = i + space_count * 2 + 1;
// New length must be smaller than length
// of string provided.
if (new_length > MAX)
return -1;
// Start filling character from end
int index = new_length - 1;
// Fill string termination.
str[index--] = '\0';
// Fill rest of the string from end
for (int j=i-1; j>=0; j--)
{
// inserts %20 in place of space
if (str[j] == ' ')
{
str[index] = '0';
str[index - 1] = '2';
str[index - 2] = '%';
index = index - 3;
}
else
{
str[index] = str[j];
index--;
}
}
return new_length;
}
// Driver code
int main()
{
char str[MAX] = "Mr John Smith ";
// Prints the replaced string
int new_length = replaceSpaces(str);
for (int i=0; i<new_length; i++)
printf("%c", str[i]);
return 0;
}`

Categories