Home > Mobile >  Codingbat challenge: mirrorEnds Stream API Solution
Codingbat challenge: mirrorEnds Stream API Solution

Time:06-07

Given the task mirrorEnds from CodingBat:

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 beginning 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 solution for this task is the following:

public String mirrorEnds(String str) {
  String result = "";
  
  if (str.length() % 2 != 0) {
    for (int i = 0; i < str.length() / 2; i  ) {
      if (str.charAt(i) == str.charAt(str.length() - i - 1)) {
        result  = ""   str.charAt(i);
      } else {
        break;
      }
    }
    
    if (result.length() == str.length() / 2) {
      String strEnd = new StringBuilder(result).reverse().toString();
      result  = ""   str.charAt(str.length() / 2)   strEnd;
    } 
  }
  
  
  if (str.length() % 2 == 0) {
    for (int i = 0; i < str.length() / 2; i  ) {
      if (str.charAt(i) == str.charAt(str.length() - i - 1)) {
        result  = ""   str.charAt(i);
      } else {
        break;
      }
    }
    
    if (result.length() == str.length() / 2) {
      String strEnd = new StringBuilder(result).reverse().toString();
      result  = strEnd;
    }
  }
  
  return result;
}

Is it possible to solve this problem using Stream API ?

CodePudding user response:

I think Stream API wouldn't give you any advantage. however, you can optimize your code like this

  public String mirrorEnds(String string) {
    StringBuilder result = new StringBuilder();

    for (int i = 0; i < string.length(); i  ) {
        if (string.charAt(i) == string.charAt(string.length() - i - 1)) {
            result.append(string.charAt(i));
        } else {
            break;
        }
    }
    return result.toString();
}

CodePudding user response:

Since you're purposely asking for a stream-solution to this problem, this could be to look for the greatest index i where the first i characters match the last i characters reversed, with i starting from length() / 2 and proceeding by decrementing i until it reaches 0.

The previous algorithm makes sense to be applied only if the given string isn't a palindrome. In fact, in that case, the string itself could be returned immediately.

public static String mirrorEnds(String str) {
    if (str.equals(new StringBuilder(str).reverse().toString())) {
        return str;
    }

    OptionalInt maxLen = IntStream.iterate(str.length() / 2, i -> i >= 0, i -> i - 1)
            .filter(i -> str.substring(0, i).equals((new StringBuilder(str.substring(str.length() - i))).reverse().toString()))
            .max();

    return maxLen.isPresent() ? str.substring(0, maxLen.getAsInt()) : null;
}

Output

ab
a
aba

Here is a link to test the code:

https://www.jdoodle.com/iembed/v0/rUL

CodePudding user response:

It's doable with IntStream.range() in a single stream-statement.

In order to create a one-liner we will need'll a help of takeWhile(), which was introduced with Java 9. takeWhile() is a so-called short-cercuit operation, i.e. it will break after the first element that doesn't match the given predicate.

public static String mirrorEnds(String str) {
    
    return IntStream.range(0, str.length())
        .takeWhile(i -> str.charAt(i) == str.charAt(str.length() - 1 - i))
        .map(str::codePointAt)
        .collect(StringBuilder::new,
            StringBuilder::appendCodePoint,
            StringBuilder::append)
        .toString();
}

Since CodingBat is still on Java 8, its compiler will complain at the code above.

  • Related