Check if index is within parentheses - java

I'm trying to create a method in Java that checks if an index of a String is contained inside parentheses. Currently I'm just checking if ) or ( comes first, but it doesn't work well for nested parentheses.
private static boolean inParentheses(String str, int index) {
int nextOpen = str.indexOf('(', index);
int nextClose = str.indexOf(')', index);
return nextClose < nextOpen && nextOpen != -1 || nextOpen == -1 && nextClose != -1;
}

So you want to first check what the first character of the string is. Lets say you have string ipwnmice and you wanted to see if it had the character ( or the character ) at the very front of it.
String yourUsername = "ipwnmice";
char first = yourUsername.charAt(0);
System.out.println(first);
output:
i
Now, if you want to see whether the first character is ( or ) just add an if statement around the code!
String parenthasis = "(Hello)"
char first = parenthasis.charAt(0);
if(first.equals("()){
//CONTAINS ( OR ) AS FIRST CHARACTER
} else{
//DOESNT CONTAIN ( OR ) AS FIRST CHARACTER
}
It might not be in the beginning of the string:
Use the .contains() method.
if(String.contains( ( || ) ){
}
That's it. Get the character of the first letter of the string, and check if it contains ( or ). If you found this answer useful, mark it best answer. If you need any more help, feel free to ask, I am happy to help.
{Rich}

If you can safely assume that the parenthesis are all closed properly, then it amounts to counting the number of open and closed parenthesis to one side of your index. If they equal out you are not in parenthesis, otherwise you are. Be wary of the answer when your index references a parenthesis though.
int open_par = 0;
for(int i=index;i--!=0;){
if(str.charAt(i)=='(')
open_par++; //count open parenthesis
if(str.charAt(i)==')')
open_par--; //count closed parenthesis
}
return open_par>0; //if open parenthesis exceeds closed parenthesis

Related

What happens when if statement goes true (in this code)?

There is a problem in codingbat.com which you're supposed to remove "yak" substring from the original string. and they provided a solution for that which I can't understand what happens when the if statement goes true!
public String stringYak(String str) {
String result = "";
for (int i=0; i<str.length(); i++) {
// Look for i starting a "yak" -- advance i in that case
if (i+2<str.length() && str.charAt(i)=='y' && str.charAt(i+2)=='k') {
i = i + 2;
} else { // Otherwise do the normal append
result = result + str.charAt(i);
}
}
return result;
}
It just adds up i by 2 and what? When it appends to the result string?
Link of the problem:
https://codingbat.com/prob/p126212
The provided solution checks for all single characters in the input string. For this i is the current index of the checked character. When the current char is not a y and also the (i+2) character is not a k the current char index is advanced by 1 position.
Example:
yakpak
012345
i
So here in the first iteration the char at i is y and i+2 is a k, so we have to skip 3 chars. Keep in mind i is advanced by 1 everytime. So i has to be increased by 2 more. After this iteration i is here
yakpak
012345
i
So now the current char is no y and this char will get added to the result string.
But it's even simpler in Java as this functionality is build in with regex:
public String stringYak(String str) {
return str.replaceAll("y.k","");
}
The . means every char.
If i is pointing at a y and there is as k two positions down, then it wants to skip the full y*k substring, so it add 2 to i so i now refers to the k. WHen then loop continues, i++ will skip past the k, so in effect, the entire 3-letter y*k substring has been skipped.

finding the middle index of a substring when there are duplicates in the string

I was working on a Java coding problem and encountered the following issue.
Problem:
Given a string, does "xyz" appear in the middle of the string? To define middle, we'll say that the number of chars to the left and right of the "xyz" must differ by at most one
xyzMiddle("AAxyzBB") → true
xyzMiddle("AxyzBBB") → false
My Code:
public boolean xyzMiddle(String str) {
boolean result=false;
if(str.length()<3)result=false;
if(str.length()==3 && str.equals("xyz"))result=true;
for(int j=0;j<str.length()-3;j++){
if(str.substring(j,j+3).equals("xyz")){
String rightSide=str.substring(j+3,str.length());
int rightLength=rightSide.length();
String leftSide=str.substring(0,j);
int leftLength=leftSide.length();
int diff=Math.abs(rightLength-leftLength);
if(diff>=0 && diff<=1)result=true;
else result=false;
}
}
return result;
}
Output I am getting:
Running for most of the test cases but failing for certain edge cases involving more than once occurence of "xyz" in the string
Example:
xyzMiddle("xyzxyzAxyzBxyzxyz")
My present method is taking the "xyz" starting at the index 0. I understood the problem. I want a solution where the condition is using only string manipulation functions.
NOTE: I need to solve this using string manipulations like substrings. I am not considering using list, stringbuffer/builder etc. Would appreciate answers which can build up on my code.
There is no need to loop at all, because you only want to check if xyz is in the middle.
The string is of the form
prefix + "xyz" + suffix
The content of the prefix and suffix is irrelevant; the only thing that matters is they differ in length by at most 1.
Depending on the length of the string (and assuming it is at least 3):
Prefix and suffix must have the same length if the (string's length - the length of xyz) is even. In this case:
int prefixLen = (str.length()-3)/2;
result = str.substring(prefixLen, prefixLen+3).equals("xyz");
Otherwise, prefix and suffix differ in length by 1. In this case:
int minPrefixLen = (str.length()-3)/2;
int maxPrefixLen = minPrefixLen+1;
result = str.substring(minPrefixLen, minPrefixLen+3).equals("xyz") || str.substring(maxPrefixLen, maxPrefixLen+3).equals("xyz");
In fact, you don't even need the substring here. You can do it with str.regionMatches instead, and avoid creating the substrings, e.g. for the first case:
result = str.regionMatches(prefixLen, "xyz", 0, 3);
Super easy solution:
Use Apache StringUtils to split the string.
Specifically, splitByWholeSeparatorPreserveAllTokens.
Think about the problem.
Specifically, if the token is in the middle of the string then there must be an even number of tokens returned by the split call (see step 1 above).
Zero counts as an even number here.
If the number of tokens is even, add the lengths of the first group (first half of the tokens) and compare it to the lengths of the second group.
Pay attention to details,
an empty token indicates an occurrence of the token itself.
You can count this as zero length, count as the length of the token, or count it as literally any number as long as you always count it as the same number.
if (lengthFirstHalf == lengthSecondHalf) token is in middle.
Managing your code, I left unchanged the cases str.lengt<3 and str.lengt==3.
Taking inspiration from #Andy's answer, I considered the pattern
prefix+'xyz'+suffix
and, while looking for matches I controlled also if they respect the rule IsMiddle, as you defined it. If a match that respect the rule is found, the loop breaks and return a success, else the loop continue.
public boolean xyzMiddle(String str) {
boolean result=false;
if(str.length()<3)
result=false;
else if(str.length()==3 && str.equals("xyz"))
result=true;
else{
int preLen=-1;
int sufLen=-2;
int k=0;
while(k<str.lenght){
if(str.indexOf('xyz',k)!=-1){
count++;
k=str.indexOf('xyz',k);
//check if match is in the middle
preLen=str.substring(0,k).lenght;
sufLen=str.substring(k+3,str.lenght-1).lenght;
if(preLen==sufLen || preLen==sufLen-1 || preLen==sufLen+1){
result=true;
k=str.length; //breaks the while loop
}
else
result=false;
}
else
k++;
}
}
return result;
}

Finding various char's within a String

I have a basic String variable that contains the letter x a total of three times.
I have attempted to find x within the String using charAt, and then print the char and the next two characters next to it.
I have hit a snag within my code and would appreciate any help.
Here is my code.
public class StringX{
public static void main(String[] args){
String ss = "xarxatxm";
char first = ss.charAt(0);
char last == ss.charAt(3);
if(first == "x"){
String findx = ss.substring(0, 2);
}
if(last == "x"){
String findX = ss.substring(3, 5);
}
System.out.print(findx + findX);
}
}
Also, is there a way to implement the for loop to cycle through the String looking for x also?
I just need some advice to see where my code is going wrong.
You cannot find characters using charAt - it's for getting a character once you know where it is.
Is there a way to implement the for loop to cycle through the String looking for x also?
You need to use indexOf for finding positions of characters. Pass the initial position which is the position of the last x that you found so far to get the subsequent position.
For example, the code below
String s = "xarxatxm";
int pos = -1;
while (true) {
pos = s.indexOf('x', pos+1);
if (pos < 0) break;
System.out.println(pos);
}
prints 0 3 6 for the three positions of 'x' in the string.

Java: Efficient way to determine if a String meets several criteria?

I would like to find an efficient way (not scanning the String 10,000 times, or creating lots of intermediary Strings for holding temporary results, or string bashing, etc.) to write a method that accepts a String and determine if it meets the following criteria:
It is at least 2 characters in length
The first character is uppercased
The remaining substring after the first character contains at least 1 lowercased character
Here's my attempt so far:
private boolean isInProperForm(final String token) {
if(token.length() < 2)
return false;
char firstChar = token.charAt(0);
String restOfToken = token.substring(1);
String firstCharAsString = firstChar + "";
String firstCharStrToUpper = firstCharAsString.toUpperCase();
// TODO: Giving up because this already seems way too complicated/inefficient.
// Ignore the '&& true' clause - left it there as a placeholder so it wouldn't give a compile error.
if(firstCharStrToUpper.equals(firstCharAsString) && true)
return true;
// Presume false if we get here.
return false;
}
But as you can see I already have 1 char and 3 temp strings, and something just doesn't feel right. There's got to be a better way to write this. It's important because this method is going to get called thousands and thousands of times (for each tokenized word in a text document). So it really really needs to be efficient.
Thanks in advance!
This function should cover it. Each char is examined only once and no objects are created.
public static boolean validate(String token) {
if (token == null || token.length() < 2) return false;
if (!Character.isUpperCase(token.charAt(0)) return false;
for (int i = 1; i < token.length(); i++)
if (Character.isLowerCase(token.charAt(i)) return true;
return false;
The first criteria is simply the length - this data is cached in the string object and is not requiring traversing the string.
You can use Character.isUpperCase() to determine if the first char is upper case. No need as well to traverse the string.
The last criteria requires a single traversal on the string- and stop when you first find a lower case character.
P.S. An alternative for the 2+3 criteria combined is to use a regex (not more efficient - but more elegant):
return token.matches("[A-Z].*[a-z].*");
The regex is checking if the string starts with an upper case letter, and then followed by any sequence which contains at least one lower case character.
It is at least 2 characters in length
The first character is
uppercased
The remaining substring after the first character contains
at least 1 lowercased character
Code:
private boolean isInProperForm(final String token) {
if(token.length() < 2) return false;
if(!Character.isUpperCase(token.charAt(0)) return false;
for(int i = 1; i < token.length(); i++) {
if(Character.isLowerCase(token.charAt(i)) {
return true; // our last criteria, so we are free
// to return on a met condition
}
}
return false; // didn't meet the last criteria, so we return false
}
If you added more criteria, you'd have to revise the last condition.
What about:
return token.matches("[A-Z].*[a-z].*");
This regular expression starts with an uppercase letter and has at least one following lowercase letter and therefore meets your requirements.
To find if the first character is uppercase:
Character.isUpperCase(token.charAt(0))
To check if there is at least one lowercase:
if(Pattern.compile("[a-z]").matcher(token).find()) {
//At least one lowercase
}
To check if first char is uppercase you can use:
Character.isUpperCase(s.charAt(0))
return token.matches("[A-Z].[a-z].");

Need some help in writing a recursive implementation for my Palindrome app

First of all I am not asking for people to "do my homework" like I have seen others on here ask for. I have managed to code a working iterative version of a program that determines if a string is a palindrome or not. Spaces, punctuation and special characters are ignored while determining if the string is a palindrome. This version does work but when I try and apply recursive statements in the "isPalindrome()" method I get Stack Overflow errors. I know what these errors are, it's just that applying a recursive method in a program like this is quite hard for me to get my head around (I only got taught about them 2 weeks ago). Anyway here is the code I have managed to compile (and run) so far:
/** Palindrome.java: A sigle application class that determines if a word or a string
* is a palindrome or not. This application is designed to ignore spaces between
* chars, punctuation marks and special characters while determining if the word or
* string is a palindrome or not.
*
**/
import java.util.Scanner;
import java.util.StringTokenizer;
import java.util.regex.*;
public class Palindrome{
static String palindrome, str, str2, str3;
/** The main method of the Palindrome application. Takes input from the
* user, removes spaces from their input, turns their string input into
* lowercase and then all non letter characters are taken out of the user's
* input. Finally the recursive method determines if the string entered in
* by the user is a palindrome.
*
* #param args Takes in a string array of arguements
**/
public static void main(String[] args){
Scanner input = new Scanner(System.in);
while(input.hasNext()){
str = removeSpaces(input.nextLine());
str2 = str.toLowerCase();
str3 = normalise(str2);
}
System.out.println(isPalindrome(str3));
}
/** The default constructor
**/
public Palindrome(){
}
/** isPalindrome(): A boolean method that is passed through a String input
* and uses a for loop, two inner while loops and an if-else to determine
* whether the users input is a palindrome.
*
* #param s The string input to be tested
* #return true The users input is a palindrome
* #return false The users input isn't a palindrome
**/
public static boolean isPalindrome(String s){
int first, last;
for(first = 0, last = s.length()-1 ; first < last ; first++ , last-- ){
while( (int)s.charAt(first) < 'a' || (int)s.charAt(first) > 'z' ){
first++;
}
while( (int)s.charAt(last ) < 'a' || (int)s.charAt(last ) > 'z' ){
last--;
}
}
if( first > last || s.charAt(first) != s.charAt(last) ){
//return isPalindrome(s.substring(0, s.length()-1)) == false;
return false;
}
else{
//return isPalindrome(s.substring(0, s.length()-1)) == true;
return true;
}
}
/**
* This method takes out punctuation marks in the string parsed
* through, using Java's regular expressions (regex) and Java's
* inbuilt method replaceAll(). The regex expression is passed
* through the replaceAll() method to remove all non alpha-numeric
* characters from the string passed through the method's parameter.
*
* #param t The string that will have punctuation stripped from it.
*
* #return t The string has had all non alpha-numeric characters
* removed and the new string is then returned.
*/
public static String normalise(String t){
t = t.replaceAll("[^a-zA-Z0-9]", "");
return t;
}
/** removeSpaces(): A method that deletes spaces from the users input
* and then decrements the string length count so any indexes aren't missed
* when it is incremented.
*
* #param s The string which is going to have it's spaces removed.
* #return temp The new string is then returned after the spaces have been taken out.
**/
public static String removeSpaces(String s){
StringBuilder temp = new StringBuilder(s); //creates a new StringBuilder with the inputted String
for(int i = 0; i < temp.length(); i++){ //do this for the entire length of the StringBuilder
if(temp.charAt(i) == ' '){ //if the char at i is a space
temp.deleteCharAt(i); //remove the char
i--; //subtract 1 from the counter so we don't miss an index when we increment it
}
}
return temp.toString(); //return the new String
}
}
I have blanked out the recursive statements in the recursive method for now. If someone can tell me what exactly I have done wrong and also help me in implementing a solution that would be really good. I would rather stick with the iterative version because I understand the mechanics of it, but have been asked to do a recursive version (I have been Java coding since after my mid year break last year but am a relative novice at recursion) which is proving to be quite a challenge. If you alter the code and it ends up working with the recursive version please explain how, when, why etc with your alterations. Am not looking for someone to just do this for me, I'm wanting to learn and it seems that I have learned best by example (I did get a B pass last year by analysing examples and reading explanations of implementations). Many thanks :).
EDIT: I think I have got the recursion going ok now, just the logic is the thing confusing me at the moment. Here is the recoded version of the isPalindrome() method:
public static boolean isPalindrome(String s){
int first, last;
boolean isPalindr = true;
if (s.length() <= 1){
return true; // Base case
}
for(first = 0, last = s.length()-1 ; first < last ; first++ , last-- ){
// while( (int)s.charAt(first) < 'a' || (int)s.charAt(first) > 'z' ){
// first++;
// }
// while( (int)s.charAt(last ) < 'a' || (int)s.charAt(last ) > 'z' ){
// last--;
// }
// }
if( first == last || s.charAt(first) == s.charAt(last) ){
//return isPalindrome(s.substring(first, last));
return isPalindrome(s.substring(first, last)) == true;
//isPalindr = false;
}
else{
return isPalindrome(s.substring(first, last)) == false;
//isPalindr = true;
}
}
return isPalindr;
}
If someone can help me with the logic I think this will be fixed :).
Removing all of the code that has nothing to do with the problem leaves us with this:
public static boolean isPalindrome(String s){
for loop {
isPalindrome();
}
}
isPalindrome calls isPalindrome calls isPalindrome, etc... infinitum.
The difference between this and a proper recursive function is that a recursive function will have some sort of conditional statement, breaking the cycle of the function calling itself. The flow of execution will go like this:
isPalindrome(1) begins execution and calls isPalidrome(2)
isPalindrome(2) begins execution and calls isPalidrome(3)
isPalindrome(3) begins execution and calls isPalidrome(4)
isPalindrome(4) begins execution and calls isPalidrome(5)
isPalindrome(5) begins execution and returns to isPalindrome(4)
isPalindrome(4) resumes execution and returns to isPalindrome(3)
isPalindrome(3) resumes execution and returns to isPalindrome(2)
isPalindrome(2) resumes execution and returns to isPalindrome(1)
isPalindrome(1) resumes execution and returns.
If that explanation doesn't help, think of it like this. Suppose someone was handing you plates, one at a time, to see if you can hold 25 plates at a time. It would go something like this:
Plate 1 is given to you. Are there 25 plates? No. Add another plate.
Plate 2 is stacked on top of Plate 1. Are there 25 plates? No. Add another plate.
Plate 3 is stacked on top of Plate 2. Are there 25 plates? No. Add another plate.
...
Plate 24 is stacked on top of Plate 23. Are there 25 plates? No. Add another plate.
Plate 25 is stacked on top of Plate 24. Are there 25 plates? Yes. Mission Accomplished. Now, let's put the plates back.
Plate 25 is removed.
Plate 24 is removed.
...
Plate 3 is removed.
Plate 2 is removed.
Plate 1 is removed.
Here's how that might be coded:
bool stackPlates(int i){
plateStack.addPlate();
if (plateStack.wasDropped == true) { return false; } // Were the plates dropped? Return FALSE to indicate failure.
else if (i < 25) { return stackPlates(i+1); } // Are there 25 plates yet? If not, add another.
else { return true; } // There are 25 plates stacked. Return TRUE to indicate success.
plateStack.removePlate(i);
}
Here's stackPlates(int i) called from another function:
bool success = stackPlates(1);
if (success==TRUE) { cout << "CONGRATULATIONS! YOU STACKED 25 PLATES!"; }
else { cout << "YOU BROKE THE PLATES! BETTER LUCK NEXT TIME!"; }
What your function needs to do in order to work properly is do this:
bool isPalindrome(string s, int i) {
char first = s[i]; // REPLACE THIS WITH THE CODE TO SKIP SPACES & SPECIAL CHARACTERS
char last = s[(s.length -1) -i]; // REPLACE THIS WITH THE CODE TO SKIP SPACES & SPECIAL CHARACTERS
if ( first != last ) { return false; } // return false if mismatch letter
else if ( i >= (s.length/2) ) { return true; } // return true if string fully checked
else { return isPalindrome(s, i+1); } // string not fully checked; move to next letter
}
You're experiencing stack overflows because the else branch at the bottom of the function is executed when (first <= last && "characters are equals"), so you keep recurring on the case where your string is composed by one character.
By the way, I think your code is not using recursion cleanly: you should preprocess your string only one time before starting recurring on the string, and the code that performs the palindrome recursion should be far simpler.
For any given entry into isPalindrome, it's going to recursively call itself regardless because you have no condition on your else. So, if it meets the criteria "first > last || s.charAt(first) != s.charAt(last)", it's going to recursively call isPalindrome, then the next call is too, even if it hits the else.
I don't know what a Palindrome is or what the real solution to the problem is, but that's why you're getting the stack overflow error. I suspect you need to add another condition to your else such that it will stop recursively calling itself.
When writing a recursive function the best way to go about this is usually to decide on a base case (:like "" is a palindrome, though so is "a" ... ) and then devise a method to take any state and move it to the base case.
So in the case of the palindrome, it's the same basic idea as before, if the first character and the last character are the same you return true and check the rest of the string ( thus moving closer to the base case ) and if they are not then you return false.
Your stack overflow comes from calling isPalindrome in every case rather than when you need to continue solving the problem, don't forget that if two characters mean that something isn't a palindrome, the rest is rendered irrelevant ( and thus needn't be recursed on )
Your recoded version is a bit strange, because it's still using a loop when it doesn't need to. In particular, your code will never go beyond the first iteration in your loop, because in the embedded if-else statement, you're going to return a result no matter what, so your function will always exit during the first iteration (unless there are no iterations at all).
Recursion should be approached by
Identifying a base case, i.e. a simplest case that can be solved
Re-representing a larger problem as a partial solution followed by the same, but smaller problem.
The base case you've handled correctly; any String which is length 1 or less is automatically a Palindrome.
The next step is to consider a larger problem, perhaps some string abcwewe....ba. How can we break this down into a simpler problem? We know that we'd normally check whether something is a palindrome by checking the letters one by one in pairs, starting at the ends, but then we also realise that each time we check the letters, we just repeat the same problem again and solve it the same way.
In the string I gave above, we check and verify that the first letter a is the same as the last letter a, so that's kind of a partial solution. Now we we end up with is the smaller word bcwewe....b, and it's the same problem again: Is this new String a palindrome also?
Thus, all you have to do now is to invoke the recursive call, but this time with the substring beginning with the 2nd character to the 2nd to last character. You can code the answer in just two lines, as below:
public static boolean isPalindrome(String s) {
if (s.length() <= 1) return true; // base case
return s.charAt(0) == s.charAt(s.length()-1) && isPalin(s.substring(1,s.length()-1)); // recursive case
}
One point to note is that I'm using the short circuit &&, so if the first condition fails (checking first and last character), then Java will not invoke the recursion.

Categories