Repeatedly removing a substring from a string - java

Problem: Remove the substring t from a string s, repeatedly and print the number of steps involved to do the same.
Example: t = ab, s = aabb. In the first step, we check if t is contained within s. Here, t is contained in the middle i.e. a(ab)b. So, we will remove it and the resultant will be ab and increment the count value by 1. We again check if t is contained within s. Now, t is equal to s i.e. (ab). So, we remove that from s and increment the count. So, since t is no more contained in s, we stop and print the count value, which is 2 in this case.
I tried to solve this using recursion
static int maxMoves(String s, String t) {
if ( null == s || "" == s || null == t || "" == t){
return 0;
}
int i = s.indexOf(t);
if(i != -1) {
return maxMoves(s.substring(0, i)+ s.substring(i+t.length(), s.length()), t) + 1;
} else {
return 0;
}
}
But I am only passing 9/14 test cases. I also tried this,
static int maxMoves(String s, String t) {
int count = 0,i;
while(true)
{
if(s.contains(t))
{
i = s.indexOf(t);
s = s.substring(0,i) + s.substring(i + t.length());
}
else break;
++count;
}
return count;
}
But that also only passed 9/14 cases.
Could anyone help me figure out which cases I am not covering?

Simply you can use String::replaceFirst with a while loop for example:
String s = "aabb";
String t = "ab";
int count = 0;
while (s.contains(t)) {
s = s.replaceFirst(Pattern.quote(t), "");
count++;
}
System.out.println(count);

Use String#replace
String s = "aabb";
String oldstr = s;
String x = "ab";
while(s.contains(x)){
s = s.replace(x, "");
}
System.out.println((oldstr.length()-s.length())/x.length());

An easy and efficient way is to accumulate the string character-by-character in a StringBuilder; if at any time its buffer ends with the string you want to replace, remove it:
StringBuilder sb = new StringBuilder();
int c = 0;
for (int i = 0; i < s.length(); ++i) {
sb.append(s.charAt(i));
int last = sb.length()-t.length();
if (last >= 0 && sb.indexOf(t, last) == last) {
sb.setLength(last);
++c;
}
}
// c is now the number of times you removed t from s.

Related

Valid Palindrome, solution too slow for large input sizes

I am having an issue with a particular leetcode problem called Valid Palindrome. My code works for all test cases except the last test case 479/480.
In this test case a 106890 length string is passed in but my code takes too long to solve it.
I decided to try take a different approach and use the StringBuilder class to reverse the string and then simply use reversedString.equals(originalString) to compare whether they are a palindrome. This approach solves the question and passes all testcases
Why doesn't my two pointer approach work? Why does it fail on the last test case?
Here is my solution (Two Pointer)
class Solution {
public static boolean isPalindrome(String s) {
String fixedString = "";
for (char c : s.toCharArray()) {
if (Character.isDigit(c) || Character.isLetter(c)) {
fixedString += c;
}
}
fixedString = fixedString.toLowerCase();
int i = 0;
int j = fixedString.length() - 1;
System.out.println(fixedString.toCharArray());
while (i <= j) {
if (fixedString.toCharArray()[i] != fixedString.toCharArray()[j]) {
return false;
}
i += 1;
j -= 1;
}
return true;
}
}
Here is my second solution using StringBuilder.
public class Valid_Palindrome {
public static void main(String args[]){
System.out.println(isPalindrome("A man, a plan, a canal: Panama"));
}
public static boolean isPalindrome(String s) {
String fixedString = "";
for(char c : s.toCharArray()){
if(Character.isDigit(c) || Character.isLetter(c)){
fixedString += c;
}
}
fixedString = fixedString.toLowerCase();
StringBuilder sb = new StringBuilder(fixedString);
sb = sb.reverse();
System.out.println(sb);
return sb.toString().equals(fixedString);
}
}
Technically speaking, isn't the second solution supposed to be much slower since it is using StringBuilder?
How do I optimize my first solution?
Here is the input string that is passed in my leetcode.
Don't build or reverse or do anything with the string, except iterate over half its characters.
In pseudo code:
Loop over the first half of the characters
For the ith character, compare it with the (length - i - 1)th character
If different, return false
If loop ends, return true
It is generally slow to perform string concatenation in a loop. Use a StringBuilder instead in the first loop to create the filtered string.
StringBuilder sb = new StringBuilder(s.length());
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (Character.isLetterOrDigit(c))
sb.append(Character.toLowerCase(c));
}
for (int i = 0, j = sb.length() - 1; i < j; i++, j--)
if (sb.charAt(i) != sb.charAt(j))
return false;
return true;
There are a couple of statements in your code that are probably slowing it down.
fixedString += c;
This creates a new StringBuilder object. The contents of fixedString are copied to it. Then the character (c) is appended. Then the StringBuilder is converted to a String and that String is assigned to variable fixedString.
if (fixedString.toCharArray()[i] != fixedString.toCharArray()[j])
Method toCharArray creates a new char[] and copies the contents of the String to it.
I suggest that you create the char[] once only and work with it. Of-course you need to remove the non-letters and non-digits from the original string as well as convert to lower case.
Here is my rewrite of your [two pointer] solution.
(Note that I assume that a null or empty string is not a palindrome.)
public static boolean isPalindrome(String s) {
if (s != null && !s.isEmpty()) {
char[] chars = s.toCharArray();
char[] temp = new char[chars.length];
int count = 0;
for (char c : chars) {
if (Character.isDigit(c) || Character.isLetter(c)) {
temp[count++] = Character.toLowerCase(c);
}
}
char[] letters = new char[count];
System.arraycopy(temp, 0, letters, 0, count);
int i = 0;
int j = count - 1;
System.out.println(letters);
while (i < j) {
if (letters[i] != letters[j]) {
return false;
}
i++;
j--;
}
return true;
}
return false;
}

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

How to tackle the Codingbat String-2 oneTwo challenge?

Here is the problem statement:
Given a string, compute a new string by moving the first char to come after the next two chars, so "abc" yields "bca". Repeat this process for each subsequent group of 3 chars, so "abcdef" yields "bcaefd". Ignore any group of fewer than 3 chars at the end.
Here is my code:
// oneTwo("abc") → "bca"
// oneTwo("tca") → "cat"
// oneTwo("tcagdo") → "catdog"
public String oneTwo(String str) {
String x = "";
if (str.length() < 3) {
return "";
// return empty
} else if (str.length() == 3) {
String s = str.substring(1, str.length());
x = s + str.substring(0, 1); // last two + first char
} else if (str.length() > 3) {
int third = 2;
// start with the third element index of 2
for (int i = 0; i < str.length(); i++) {
if (i == third) {
// given three chars substring first char
// substring last two chars and add that to x
x += (str.substring(third - 1, third + 1) +
str.substring(third - 2, third - 2 + 1));
third += 3;
//work with this line but why??????
}
//third +=3;
// doesn't work with this line but why???????
}// end of for loop
}
return x;
// return modified string x
}
With third +=3 inside of if statement work but when I put that outside of if statement I don't get the desired output. I don't really understand why?
Hope this helps:
public String oneTwo(String str) {
String str2 = "";
for(int i=0; i<str.length()-2; i+=3) {
str2 = str2+str.substring(i+1,i+3)+str.charAt(i);
}
return str2;
}
Because putting it outside the loop will cause third to be increased far too often. After the first iteration i is 0, third is 5, next iteration yields i=1, third=8; i=2, third=11; i=3, third=14, etc. -> i will never reach third.
I would improve your code by dropping the entire if-statement, remove third all together and simply increment by 3 in the for-loop:
for( int i = 2; i < str.length(); i+=3){
x += (str.substring(third-1, third+1) +
str.substring(third-2, third-2 + 1));
}
If I am not misinterpreting your code you are missing logic for leaving the last characters alone if they are not part of group of three characters.
If you face such effects take a piece of paper and write down the values of the variables after each line of your code.
The if block creates an alternative execution path if the condition is true which is in every third loop iteration.
Anything behind the if block is executed in every loop iteration.
So when the line in question is inside the if block (before the closing brace) the value in variable third is only changed every third loop iteration.
When you move the line behind the closing brace the assignment is outside the if block and therefore executed every loop iteration.
For the comment = //work with this line but why??????
The value of "third" variable gets changed in the for loop only with i is equal to third character, otherwise the value of third will keep on increasing eg.
when i = 0, third = 2
when i = 1, third = 5
when i = 2, third = 8
so the if statement never gets triggered and hence it doesn't work. Hope this makes sense.
PS - I highly recommend using IDE debugger to understand this properly.
PS - It's better to use charAt method as compared for substring method for performance reason
public String oneTwo(String str) {
String temp = "";
String result = "";
int i = 0;
while (str.substring(i).length() >= 3) {
temp = str.substring(i, i + 3);
result += temp.substring(1) + temp.charAt(0);
i += 3;
}
return result;
}
public String oneTwo(String str) {
String str1 = "";
if(str.length()<3){
return str1;
}else if(str.length()>=3){
for(int i =0; i<str.length()-2; i=i+3){
str1 = str1 + str.substring(i+1,i+3)+ str.substring(i,i+1);
}
}
return str1;
}
public String oneTwo(String str) {
if(str.length()<3)return "";
return str.substring(1,3)+str.substring(0,1)+oneTwo(str.substring(3));
}
this is fairly simple as a recursive problem
public String oneTwo(String str) {
String newThreeChars = "";
if(str.length()<3){
return newThreeChars;
}
for(int i=0; i<str.length()/3; i+=3){
String threeChars = str.substring(i,i+3);
String redesigned = threeChars.substring(1) + threeChars.charAt(0);
newThreeChars +=redesigned;
}
return newThreeChars;
}
Another solution to look at...
public String oneTwo(String str) {
int i = 0;
String result = "";
Character tmpChar = '\0';
while(i <= str.length()-3){
tmpChar = str.charAt(i);
result = result + str.charAt(i+1) + str.charAt(i+2) + tmpChar;
tmpChar = '\0';
i = i + 3;
}
return result;
}
First, We loop through each letter of the given String just stopping shy of the last two letters because the word we are looking for is three letters long. Then, we are returning true if there is two letter "b"'s exactly one character apart.
public boolean bobThere(String str) {
for (int i = 0; i < str.length() - 2; i++) {
if (str.charAt(i) == 'b' && str.charAt(i+2) == 'b')
return true;
}
return false;
}
For string concatenation in a loop use StringBuilder:
public String oneTwo(String str) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.length() - 2; i += 3) {
sb.append(str.charAt(i + 1)).append(str.charAt(i + 2)).append(str.charAt(i));
}
return sb.toString();
}

Java: Find the longest substring without any number and at least one upper case character

Came across a programming exercise and was stuck. The problem is:
You need to define a valid password for an email but the only
restrictions are:
The password must contain one uppercase character
The password should not have numeric digit
Now, given a String, find the length of the longest substring which
is a valid password. For e.g Input Str = "a0Ba" , the output should
be 2 as "Ba" is the valid substring.
I used the concept of longest substring without repeating characters which I already did before but was unable to modify it to find the solution to above problem. My code for longest substring without repeating characters is:
public int lengthOfLongestSubstring(String s) {
int n = s.length();
Set<Character> set = new HashSet<>();
int ans = 0, i = 0, j = 0;
while (i < n && j < n) {
// try to extend the range [i, j]
if (!set.contains(s.charAt(j))){
set.add(s.charAt(j++));
ans = Math.max(ans, j - i);
}
else {
set.remove(s.charAt(i++));
}
}
return ans;
}
How about
final String input = "a0Ba";
final int answer = Arrays.stream(input.split("[0-9]+"))
.filter(s -> s.matches("(.+)?[A-Z](.+)?"))
.sorted((s1, s2) -> s2.length() - s1.length())
.findFirst()
.orElse("")
.length();
out.println(answer);
Arrays.stream(input.split("[0-9]+")) splits the original string into an array of strings. The separator is any sequence of numbers (numbers aren't allowed so they serve as separators). Then, a stream is created so I can apply functional operations and transformations.
.filter(s -> s.matches("(.+)?[A-Z](.+)?")) keeps into the stream only strings that have at least one upper-case letter.
.sorted((s1, s2) -> s2.length() - s1.length()) sorts the stream by length (desc).
.findFirst() tries to get the first string of the stream.
.orElse("") returns an empty string if no string was found.
.length(); gets the length of the string.
I suggest that you split your String to have an array of strings without digit:
yourString.split("[0-9]")
Then iterate over this array (says array a) to get the longest string that contains one Upper case character:
a[i].matches("[a-z]*[A-Z]{1}[a-z]*");
You can use a simple array. The algorithm to use would be a dynamic sliding window. Here is an example of a static sliding window: What is a Sliding Window
The algorithm should be as follows:
Keep track of 2 indexes of the array of char. These 2 indexes will be referred to as front and back here, representing the front and back of the array.
Have an int (I'll name it up here) to keep track of the number of upper case char.
Set all to 0.
Use a while loop that terminates if front > N where N is the number of char given.
If the next char is not a number, add 1 to front. Then check if that char is upper case. If so, add 1 to up.
If up is at least 1, update the maximum length if necessary.
If the next char is a number, continue checking the following char if they are also numbers. Set front to the first index where the char is not a number and back to front-1.
Output the maximum length.
You can use my solution which runs in O(n) time and finds the longest part without any digit and with a capital letter:
String testString = "skjssldfkjsakdfjlskdssfkjslakdfiop7adfaijsldifjasdjfil8klsasdfŞdijpfjapodifjpoaidjfpoaidjpfi9a";
int startIndex = 0;
int longestStartIndex = 0;
int endIndex = 0;
int index = 0;
int longestLength = Integer.MIN_VALUE;
boolean foundUpperCase = false;
while(index <= testString.length()) {
if (index == testString.length() || Character.isDigit(testString.charAt(index))) {
if (foundUpperCase && index > startIndex && index - startIndex > longestLength) {
longestLength = index - startIndex;
endIndex = index;
longestStartIndex = startIndex;
}
startIndex = index + 1;
foundUpperCase = false;
} else if (Character.isUpperCase(testString.charAt(index))) {
foundUpperCase = true;
}
index++;
}
System.out.println(testString.substring(longestStartIndex, endIndex));
You don't need regular expressions. Just use a few integers to act as index pointers into the string:
int i = 0;
int longestStart = 0;
int longestEnd = 0;
while (i < s.length()) {
// Skip past all the digits.
while (i < s.length() && Character.isDigit(s.charAt(i))) {
++i;
}
// i now points to the start of a substring
// or one past the end of the string.
int start = i;
// Keep a flag to record if there is an uppercase character.
boolean hasUppercase = false;
// Increment i until you hit another digit or the end of the string.
while (i < s.length() && !Character.isDigit(s.charAt(i))) {
hasUppercase |= Character.isUpperCase(s.charAt(i));
++i;
}
// Check if this is longer than the longest so far.
if (hasUppercase && i - start > longestEnd - longestStart) {
longestEnd = i;
longestStart = start;
}
}
String longest = s.substring(longestStart, longestEnd);
Ideone demo
Whilst more verbose than regular expressions, this has the advantage of not creating any unnecessary objects: the only object created is the longest string, right at the end.
I am using modification of Kadane algorithm to search the required password length. You may use isNumeric() and isCaps() function or include inline if statements. I have shown below with functions.
public boolean isNumeric(char x){
return (x>='0'&&x<='9');
}
public boolean isCaps(char x){
return (x>='A'&&x<='Z');
}
public int maxValidPassLen(String a)
{
int max_so_far = 0, max_ending_here = 0;
boolean cFlag = false;
int max_len = 0;
for (int i = 0; i < a.length(); i++)
{
max_ending_here = max_ending_here + 1;
if (isCaps(a.charAt(i))){
cFlag = true;
}
if (isNumeric(a.charAt(i))){
max_ending_here = 0;
cFlag = false;
}
else if (max_so_far<max_ending_here){
max_so_far = max_ending_here;
}
if(cFlag&&max_len<max_so_far){
max_len = max_so_far;
}
}
return max_len;
}
Hope this helps.
There are plenty of good answers here but thought it might be of interest to add one that uses Java 8 streams:
IntStream.range(0, s.length()).boxed()
.flatMap(b -> IntStream.range(b + 1, s.length())
.mapToObj(e -> s.substring(b, e)))
.filter(t -> t.codePoints().noneMatch(Character::isDigit))
.filter(t -> t.codePoints().filter(Character::isUpperCase).count() == 1)
.mapToInt(String::length).max();
If you wanted the string (rather than just the length), then the last line can be replaced with:
.max(Comparator.comparingInt(String::length));
Which returns an Optional<String>.
I'd use Streams and Optionals:
public static String getBestPassword(String password) throws Exception {
if (password == null) {
throw new Exception("Invalid password");
}
Optional<String> bestPassword = Stream.of(password.split("[0-9]"))
.filter(TypeErasure::containsCapital)
.sorted((o1, o2) -> o1.length() > o2.length() ? 1 : 0)
.findFirst();
if (bestPassword.isPresent()) {
return bestPassword.get();
} else {
throw new Exception("No valid password");
}
}
/**
* Returns true if word contains capital
*/
private static boolean containsCapital(String word) {
return word.chars().anyMatch(Character::isUpperCase);
}
Be sure to write some unit tests
public String pass(String str){
int length = 0;
boolean uppercase = false;
String s= "";
String d= "";
for(int i=0;i<str.length();i++){
if(Character.isUpperCase(str.charAt(i)) == true){
uppercase = true;
s = s+str.charAt(i);
}else if(Character.isDigit(str.charAt(i)) == true ){
if(uppercase == true && s.length()>length){
d = s;
s = "";
length = s.length();
uppercase = false;
}
}else if(i==str.length()-1&&Character.isDigit(str.charAt(i))==false){
s = s + str.charAt(i);
if(uppercase == true && s.length()>length){
d = s;
s = "";
length = s.length();
uppercase = false;
}
}else{
s = s+str.charAt(i);
}
}
return d;}
Here is a simple solution with Scala
def solution(str: String): Int = {
val strNoDigit = str.replaceAll("[0-9]", "-")
strAlphas = strNoDigit.split("-")
Try(strAlphas.filter(_.trim.find(_.isUpper).isDefined).maxBy(_.size))
.toOption
.map(_.length)
.getOrElse(-1)
}
Another solution using tail recursion in Scala
def solution2(str: String): Int = {
val subSt = new ListBuffer[Char]
def checker(str: String): Unit = {
if (str.nonEmpty) {
val s = str.head
if (!s.isDigit) {
subSt += s
} else {
subSt += '-'
}
checker(str.tail)
}
}
checker(str)
if (subSt.nonEmpty) {
val noDigitStr = subSt.mkString.split("-")
Try(noDigitStr.filter(s => s.nonEmpty && s.find(_.isUpper).isDefined).maxBy(_.size))
.toOption
.map(_.length)
.getOrElse(-1)
} else {
-1
}
}
This is a dynamic programming problem. You can solve this yourself using a matrix. It is easy enough. Just give it a try. Take the characters of the password as the rows and columns of the matrix. Add the diagonals if the current character appended to the last character forms a valid password. Start with the smallest valid password as the initial condition.
String[] s = testString.split("[0-9]");
int length = 0;
int index = -1;
for(int i=0; i< s.length; i++){
if(s[i].matches("[a-z]*.*[A-Z].*[a-z]*")){
if(length <= s[i].length()){
length = s[i].length();
index = i;
}
}
}
if(index >= 0){
System.out.println(s[index]);
}
//easiest way to do it:
String str = "a0Ba12hgKil8oPlk";
String[] str1 = str.split("[0-9]+");
List<Integer> in = new ArrayList<Integer>();
for (int i = 0; i < str1.length; i++) {
if (str1[i].matches("(.+)?[A-Z](.+)?")) {
in.add(str1[i].length());
} else {
System.out.println(-1);
}
}
Collections.sort(in);
System.out.println("string : " + in.get(in.size() - 1));
This is my solution with c#. I tested a range of strings and it gave me the correct value. Used Split. No Regex or Substrings. Let me know if it works; open to improvements and corrections.
public static int validPassword(string str)
{
List<int> strLength = new List<int>();
if (!(str.All(Char.IsDigit)))
{
//string str = "a0Bb";
string[] splitStrs = str.Split(new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' });
//check if each string contains a upper case
foreach (string s in splitStrs)
{
//Console.WriteLine(s);
if (s.Any(char.IsUpper) && s.Any(char.IsLower) || s.Any(char.IsUpper))
{
strLength.Add(s.Length);
}
}
if (strLength.Count == 0)
{
return -1;
}
foreach (int i in strLength)
{
//Console.WriteLine(i);
}
return strLength.Max();
}
else
{
return -1;
}
}
I think this solution takes care of all the possible corner cases. It passed all the test cases in an Online Judge. It is a dynamic sliding window O(n) solution.
public class LongestString {
public static void main(String[] args) {
// String testString = "AabcdDefghIjKL0";
String testString = "a0bb";
int startIndex = 0, endIndex = 0;
int previousUpperCaseIndex = -1;
int maxLen = 0;
for (; endIndex < testString.length(); endIndex++) {
if (Character.isUpperCase(testString.charAt(endIndex))) {
if (previousUpperCaseIndex > -1) {
maxLen = Math.max(maxLen, endIndex - startIndex);
startIndex = previousUpperCaseIndex + 1;
}
previousUpperCaseIndex = endIndex;
} else if (Character.isDigit(testString.charAt(endIndex))) {
if (previousUpperCaseIndex > -1) {
maxLen = Math.max(maxLen, endIndex - startIndex);
}
startIndex = endIndex + 1;
previousUpperCaseIndex = -1;
}
}
if (previousUpperCaseIndex > -1)
maxLen = Math.max(maxLen, endIndex - startIndex);
System.out.println(maxLen);
}}
function ValidatePassword(password){
var doesContainNumber = false;
var hasUpperCase = false;
for(var i=0;i<password.length;i++){
if(!isNaN(password[i]))
doesContainNumber = true;
if(password[i] == password[i].toUpperCase())
hasUpperCase = true;
}
if(!doesContainNumber && hasUpperCase)
return true;
else
return false;
}
function GetLongestPassword(inputString){
var longestPassword = "";
for(var i=0;i<inputString.length-1;i++)
{
for (var j=i+1;j<inputString.length;j++)
{
var substring = inputString.substring(i,j+1);
var isValid = ValidatePassword(substring);
if(isValid){
if(substring.length > longestPassword.length)
{
longestPassword = substring;
}
}
}
}
if(longestPassword == "")
{
return "No Valid Password found";
}
else
{
return longestPassword;
}
}

Java string index out of bounds in for loop (codingbat function mirrorEnds)

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

Categories