Here is the problem from codingbat.com that I am having trouble understanding the solution to.
Given a string, return a version where all the "x" have been removed.
Except an "x" at the very start or end should not be removed.
stringX("xxHxix") → "xHix"
stringX("abxxxcd") → "abcd"
stringX("xabxxxcdx") → "xabcdx"
Here is the solution they provided:
public String stringX(String str) {
String result = "";
for (int i=0; i<str.length(); i++) {
// Only append the char if it is not the "x" case
if (!(i > 0 && i < (str.length()-1) && str.substring(i, i+1).equals("x"))) {
result = result + str.substring(i, i+1); // Could use str.charAt(i) here
}
}
return result;
}
If someone could break down the complex logic in the if statement, it would be really helpful. Does the negation operator(!) apply to the entire if statement or only to what's inside of the first set of parenthesis? That if statement is what's really confusing me.
Thank you in advance.
For clarity, let us reformat the if statement:
if (
!(
i > 0
&& i < (str.length()-1)
&& str.substring(i, i+1).equals("x")
)
)
i > 0 && i < (str.length()-1) checks that the element is between the two end indexes of the String.
str.substring(i, i+1).equals("x") checks if the current element has value 'x'.
Finally, the negation applies to the logical AND of the above 2 statements.
In plain English this would be, "Append the current letter to your string, either if it is at one of the ends, or if it is between the extremes and not equal to x".
The above code would be the same as negating each part as in
if (i != 0 && i != str.length() -1 && !str.substring(i, i+1).equals("x")) {
result = result + str.substring(i, i+1); // Could use str.charAt(i) here
}
public String stringX(String str) {
int len = str.length();
String word = "";
for (int i=0; i<len; i++){
if (!(i>0 && i < len-1 && str.charAt(i)=='x')){
word += str.charAt(i);
}
}
return word;
}
i hope u will like the below code:
public static String stringX(String str) {
if(str.length()<2){
return str;
}
String sub_first = str.substring(0, 1);
String sub_last = str.substring(str.length() - 1);
String sub_mid = str.substring(1, str.length() - 1);
for (int i = 0; i < sub_mid.length(); i++) {
if (sub_mid.charAt(i) == 'x') {
sub_mid = sub_mid.replace("x", "");
}
}
return sub_first + sub_mid + sub_last;
}
Better Consider this Solution.
The Below Solution is same as given by you with more clarity.
StrHasChanged - Check whether String contains 'X'.
Then iterate from second till last before character.
if StrHasChanged is false return Original string OR return modified String.
public String stringX(String str) {
String newStr = "";
Boolean StrHasChanged = false;
if (str.length() > 1) {
for (int itr = 1; itr < str.length()-1; itr ++) {
if (str.charAt(itr) != 'x') {
StrHasChanged = true;
newStr = newStr + Character.toString(str.charAt(itr));
}
}
}
return ((str.length() == 1) || (!(StrHasChanged))) ? str : Character.toString(str.charAt(0)) + newStr + Character.toString( str.charAt(str.length()-1) );
}
public String stringX(String str) {
if (str.length() <= 3)
return str;
else {
String c = str.substring(0, 1);
String d = str.substring(str.length() - 1, str.length());
String a = str.replaceAll("x", "");
if ((c.equals("x")) && (d.equals("x")))
return c + a + d;
else if (c.equals("x"))
return c + a;
else if (d.equals("x"))
return a + d;
else
return a;
}
}
Related
I am trying to convert this Python Solution in Java. For some reason, my Java Solution is not working. How can this be done correctly?
https://leetcode.com/problems/decode-string/description/
Given an encoded string, return its decoded string. The encoding rule is: k[encoded_string], where the encoded_string inside the square brackets is being repeated exactly k times. Note that k is guaranteed to be a positive integer.
You may assume that the input string is always valid; there are no extra white spaces, square brackets are well-formed, etc. Furthermore, you may assume that the original data does not contain any digits and that digits are only for those repeat numbers, k. For example, there will not be input like 3a or 2[4].
The test cases are generated so that the length of the output will never exceed 105.
Example 1:
Input: s = "3[a]2[bc]"
Output: "aaabcbc"
Example 2:
Input: s = "3[a2[c]]"
Output: "accaccacc"
Python Solution:
class Solution:
def decodeString(self, s: str) -> str:
stack = []
for char in s:
if char is not "]":
stack.append(char)
else:
sub_str = ""
while stack[-1] is not "[":
sub_str = stack.pop() + sub_str
stack.pop()
multiplier = ""
while stack and stack[-1].isdigit():
multiplier = stack.pop() + multiplier
stack.append(int(multiplier) * sub_str)
return "".join(stack)
Java Attempt:
class Solution {
public String decodeString(String s) {
Deque<String> list = new ArrayDeque<String>();
String subword = "";
String number = "";
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) != ']' ) {
list.add(String.valueOf(s.charAt(i)));
}
else {
subword = "";
while (list.size() > 0 && !list.getLast().equals("[") ) {
subword = list.pop() + subword;
}
if (list.size() > 0) list.pop();
number = "";
while (list.size() > 0 && isNumeric(list.getLast())){
number = list.pop() + number;
}
for (int j = 1; (isNumeric(number) && j <= Integer.parseInt(number)); j++) list.add(subword);
}
}
return String.join("", list);
}
public static boolean isNumeric(String str) {
try {
Double.parseDouble(str);
return true;
} catch(NumberFormatException e){
return false;
}
}
}
The reason why your posted code is not working is because the pop() method in python removes the last element by default.
But in Java, the ArrayDeque class's pop() method removes the first element.
In order to emulate the python code with the ArrayDeque, you'll need to use the removeLast() method of the ArrayDeque instance instead.
public class Solution{
public static String decodeString(String s) {
StringBuilder stack = new StringBuilder();
for(char c : s.toCharArray()) {
if(c != ']') {
stack.append(c);
} else {
StringBuilder sub_str = new StringBuilder();
while(stack.charAt(stack.length() - 1) != '[') {
sub_str.insert(0, stack.charAt(stack.length() - 1));
stack.deleteCharAt(stack.length() - 1);
}
stack.deleteCharAt(stack.length() - 1);
StringBuilder multiplier = new StringBuilder();
while(stack.length() > 0 && Character.isDigit(stack.charAt(stack.length() - 1))) {
multiplier.insert(0, stack.charAt(stack.length() - 1));
stack.deleteCharAt(stack.length() - 1);
}
for(int i = 0; i < Integer.parseInt(multiplier.toString()); i++) {
stack.append(sub_str);
}
}
}
return stack.toString();
}
public static void main(String[] args) {
System.out.println( decodeString("3[a2[c]]"));
//Output: "accaccacc"
System.out.println( decodeString("3[a]2[bc]"));
//Output: "aaabcbc"
}
}
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;
}
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
I have a question regarding the problem at codingbat in String 3. Question is as follows:
Given a string, look for a mirror image (backwards) string at both the
beginning and end of the given string. In other words, zero or more
characters at the very begining of the given string, and at the very
end of the string in reverse order (possibly overlapping).
For example, the string "abXYZba" has the mirror end "ab"
mirrorEnds("abXYZba") → "ab"
mirrorEnds("abca") → "a"
mirrorEnds("aba") → "aba"
My code is as follows:
public String mirrorEnds(String string) {
if(string.length() <=1) return string;
String x = "";
int y = string.length() - 1;
for(int i = 0; i < string.length()/2; i++)
{
if(string.charAt(i) == string.charAt(y))
{
x+= Character.toString(x.charAt(i));
y--;
}
else
{
return x;
}
}
return string;
}
When I try it for the following:
"xxYxx"
String length is 5 so index from 0-4. If I run it on my code, the logic will be:
i = 0 and y = 4;
string.charAt(i) == string.charAt(y) //true and i++ and y--
string.charAt(i) == string.charAt(y) //true and i++ and y--
//i is == string.length()/2 at this point
But the problem throws me an error saying indexoutofbounds. Why is this the case?
You are accessing the ith character of the wrong string here:
x += Character.toString(x.charAt(i));
The String x is empty at first, so the character at index 0 doesn't exist.
Access the original string instead.
x += Character.toString(string.charAt(i));
Here my code for this problem , simple one
public String mirrorEnds(String string) {
int start = 0;
int end = string.length()-1;
for(int i=0;i<string.length();i++){
if(string.charAt(start) == string.charAt(end) ){
start++;
end--;
}
if(start != ((string.length()-1)-end)){
break;
}
}
return string.substring(0,start);
}
public String mirrorEnds(String string) {
String g="";
for(int i=0;i<string.length();i++){
if(string.charAt(i)==string.charAt(string.length()-1-i)){
g=g+string.charAt(i);
} else{
break;
}
}
return g;
}
You have a good start, but I think you should consider an even simpler approach. You only need to use one index (not both i and y) to keep track of where you are in the string because the question states that overlapping is possible. Therefore, you do not need to run your for loop until string.length() / 2, you can have it run for the entire length of the string.
Additionally, you should consider using a while loop because you have a clear exit condition within the problem: once the string at the beginning stops being equal to the string at the end, break the loop and return the length of the string. A while loop would also use less variables and would reduce the amount of conditional operators in your code.
Here's my answer to this problem.
public String mirrorEnds(String string) {
String mirror = "";
int i = 0;
while (i < string.length() && string.charAt(i) == string.charAt(string.length() - i - 1) {
mirror += string.charAt(i);
i++;
}
return mirror;
}
Another handy tip to note is that characters can be appended to strings in Java without casting. In your first if statement within your for loop, you don't need to cast x.charAt(i) to a string using Character.toString(), you can simply append x.charAt(i) to the end of the string by writing x += x.charAt(i).
public String mirrorEnds(String str) {
StringBuilder newStr = new StringBuilder();
String result = "";
for (int i=0; i <= str.length(); i++){
newStr.append(str.substring(0, i));
if (str.startsWith(newStr.toString()) && str.endsWith(newStr.reverse().toString()))
result = str.substring(0, i);
newStr.setLength(0);
}
return result;
}
public String mirrorEnds(String string) {
// reverse given string
String reversed = "";
for (int i = string.length() - 1; i >= 0; i--) {
reversed += string.charAt(i);
}
// loop through each string simultaneously. if substring of 'string' is equal to that of 'reversed',
// assign the substring to variable 'text'
String text = "";
for (int i = 0; i <= string.length(); i++) {
if (string.startsWith(string.substring(0, i)) ==
string.startsWith(reversed.substring(0, i))) {
text = string.substring(0, i);
}
}
return text;
}
public String mirrorEnds(String string) {
String out = "";
int len = string.length();
for(int i=0,j = len-1;i<len;i++,j--)
{
if(string.charAt(i) == string.charAt(j))
out += string.charAt(i);
else
break;
}
return out;
}
I'm trying to find the shortest palindrome that one can create from S by by adding 0 or more characters in front of it. For example the shortest palindrome can be constructed from 'baaa' is 'aaabaaa'. The two functions that I'm using are given below. This works for this case for doesn't yield the shortest result in all cases.
public static boolean checkPalindrome(String s){
for (int i = 0; i < s.length()/2; i++) {
if (s.charAt(i) != s.charAt(s.length() - i - 1)) return false;
}
return true;
}
public static int makePalindrome(String s){
int min = 0;
StringBuilder str = new StringBuilder(s);
for (int i = 1; i < s.length() ; i++) {
str.insert(0, s.charAt(i));
if (checkPalindrome(str.toString()) == true) {
min = str.length();
break;
}
}
return min;
}
I can't seem to figure out what logical step am I missing.
Your helper method checkPalindrome seems correct. Your thinking is also correct (append characters until the result is a palindrome), but the way you're going about it is wrong.
To reiterate: Our logic is, while our result is not a palindrome, take the next character from the end (moving towards the start of the string) and append it to the prefix. So for the string "abcd", we would try
"" + "abcd" -> "abcd" -> false
"d" + "abcd" -> "dabcd" -> false
"dc" + "abcd" -> "dcabcd" -> false
"dcb" + "abcd" -> "dcbabcd" -> true, terminate
Here's a fixed version:
public static String makePalindrome(String base){
String pref = "";
int i = base.length() - 1;
while(! checkPalindrome(pref + base)){
pref = pref + base.charAt(i);
i --;
}
return pref + base;
}
I am not sure i understand the question but from what i understood you want to turn Strings like Hello to olleHello To do this, loop trhough each char of the string with like:
String example = "Hello There Mate"; //our string
StringBuilder exampleBuilder = new StringBuilder();
for(int i=example.length()-1; i>0; i--)
exampleBuilder.append(example.charAt(i));
//Our loop, the reason why it is example.lenght-1
//is because we want the first letter to appear only
//1 time :)
String finalString = exampleBuilder.toString()+example;
//The final string, should be 'olleHello'
System.out.println(finalString);
Hope thats what you are looking for :D
IDEONE: http://ideone.com/tawjmG
We can find the shortest Palindrome using the following logic:
Find the midpoint, loop from 0 to midpoint, length-1 to midpoint.
If palindrome, return
If not palindrome, add 1 to midpoint, do same logic
In code:
static String shortestPalindrome(String s) {
if (s.length() == 1) return s;
return recShortestPalindrome(s, s.length()>>1, 0);
}
static String recShortestPalindrome(String s, int mid, int add) {
// AABBA[X]
int fakeLen = s.length() + add;
for (int i = 0; i < mid; i++) {
char c1 = s.charAt(i);
int p1 = fakeLen - 1 - i;
if (p1 < s.length()) {
char c2 = s.charAt(p1);
if (c2 != c1) {
return recShortestPalindrome(s, mid+1, add+1);
}
}
}
// found a pattern that works
String h1 = s.substring(0, mid);
String h2 = new StringBuilder(h1).reverse().toString();
String ret = h1+h2;
int midPoint = ret.length()/2;
if (ret.length()%2 == 0 && ret.length() >= 2) {
char c1 = ret.charAt(midPoint);
char c2 = ret.charAt(midPoint-1);
if (c1 == c2) {
return ret.substring(0, midPoint) + ret.substring(midPoint+1, ret.length());
}
}
return h1+h2;
}
Python Solution:
def isPalindrome(x):
if x == "":
return False
r = ""
r = str(x)
r = r[::-1]
return True if x == r else False
def makePalindrome(my_str):
pref = ""
i = len(my_str) - 1
while isPalindrome(pref + my_str) == False:
pref = pref + my_str[i]
i -= 1
return pref + my_str
my_str = "abcd"
print(makePalindrome(my_str))