I am trying to check if a string is a palindrome, but it seems it does not work, because when I send a string that I know is not a palindrome, it returns that it is a palindrome, can anyone help? It also won't add to the variable counter.
package UnaryStack.RubCol1183;
public class CheckPalindrome {
static int counter = 0;
/** Decides whether the parentheses, brackets, and braces
in a string occur in left/right pairs.
#param expression a string to be checked
#return true if the delimiters are paired correctly */
public static boolean checkBalance(String expression)
{
StackInterface<Character> temporaryStack = new LinkedStack<Character>();
StackInterface<Character> reverseStack = new LinkedStack<Character>();
StackInterface<Character> originalStack = new LinkedStack<Character>();
int characterCount = expression.length();
boolean isBalanced = true;
int index = 0;
char nextCharacter = ' ';
for (;(index < characterCount); index++)
{
nextCharacter = expression.charAt(index);
switch (nextCharacter)
{
case '.': case '?': case '!': case '\'': case ' ': case ',':
break;
default:
{
{
reverseStack.push(nextCharacter);
temporaryStack.push(nextCharacter);
originalStack.push(temporaryStack.pop());
}
{
char letter1 = Character.toLowerCase(originalStack.pop());
char letter2 = Character.toLowerCase(reverseStack.pop());
isBalanced = isPaired(letter1, letter2);
if(isBalanced == false){
counter++;
}
}
break;
}
} // end switch
} // end for
return isBalanced;
} // end checkBalance
// Returns true if the given characters, open and close, form a pair
// of parentheses, brackets, or braces.
private static boolean isPaired(char open, char close)
{
return (open == close);
} // end isPaired
public static int counter(){
return counter;
}
}//end class
Your implementation seems way more complex than it needs to be.
//Check for invalid characters first if needed.
StackInterface<Character> stack = new LinkedStack<Character>();
for (char ch: expression.toCharArray()) {
Character curr = new Character(ch);
Character peek = (Character)(stack.peek());
if(!stack.isEmpty() && peek.equals(curr)) {
stack.pop();
} else {
stack.push(curr)
}
}
return stack.isEmpty();
Honestly using a stack is over kill here. I would use the following method.
int i = 0;
int j = expression.length() - 1;
while(j > i) {
if(expression.charAt(i++) != expression.charAt(j--)) return false;
}
return true;
You put exaclty the same elemets in reverseStack and originalStack, because everything you push into the temporaryStack will be immediately pushed into originalStack. This does not make sense.
reverseStack.push(nextCharacter);
temporaryStack.push(nextCharacter);
originalStack.push(temporaryStack.pop());
Therefore the expression
isBalanced = isPaired(letter1, letter2);
will always return true.
I found the errors in logic that were found inside the method checkBalace() and finished the code into a full working one. Here is what my finished code looks like:
public class CheckPalindrome {
static int counter;
/** Decides whether the parentheses, brackets, and braces
in a string occur in left/right pairs.
#param expression a string to be checked
#return true if the delimiters are paired correctly */
public static boolean checkBalance(String expression)
{
counter = 0;
StackInterface<Character> temporaryStack = new LinkedStack<Character>();
StackInterface<Character> reverseStack = new LinkedStack<Character>();
StackInterface<Character> originalStack = new LinkedStack<Character>();
boolean isBalanced = true;
int characterCount = expression.length();
int index = 0;
char nextCharacter = ' ';
for (;(index < characterCount); index++)
{
nextCharacter = expression.charAt(index);
switch (nextCharacter)
{
case '.': case '?': case '!': case '\'': case ' ': case ',':
break;
default:
{
{
reverseStack.push(nextCharacter);
temporaryStack.push(nextCharacter);
}
break;
}
} // end switch
} // end for
while(!temporaryStack.isEmpty()){
originalStack.push(temporaryStack.pop());
}
while(!originalStack.isEmpty()){
char letter1 = Character.toLowerCase(originalStack.pop());
char letter2 = Character.toLowerCase(reverseStack.pop());
isBalanced = isPaired(letter1, letter2);
if(isBalanced == false){
counter++;
}
}
return isBalanced;
} // end checkBalance
// Returns true if the given characters, open and close, form a pair
// of parentheses, brackets, or braces.
private static boolean isPaired(char open, char close)
{
return (open == close);
} // end isPaired
public static int counter(){
return counter;
}
}
I used 2 while methods outside of the for thus fixing the logic errors pointed out. I also assigned the value 0 to counter inside the method to fix a small problem I encountered. Feel free to revise the code if I still have errors, but I think I made no errors, then again, I'm a beginner.
Related
How do I make the method indexOfVowel to return 1 for strings such as translate? I need it to find all the consonant that is before a vowel to be moved to the end. If I changed "notVowel" to 2 the word "translate" should be "anslatetray" but it returns ranslatetay. It only checks the first letter but not the rest of the word.
private String translateWord(String word) {
String translated = "";
int vowel = 0;
int notVowel = 1;
if (vowel == indexOfVowel(word)) {
return (word + "way ");
}
if (notVowel == indexOfVowel(word)) {
return (word.substring(1) + word.substring(vowel, 1) + "ay ");
}
return translated;
}
private static int indexOfVowel(String word) {
int index = 0;
for (int i = 0; i < word.length(); i++) {
if (isVowel(word.charAt(i))) {
return i;
}
}
return word.length();
}
private static boolean isVowel(char ch) {
switch (ch) {
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
return true;
default:
return false;
}
}
}
I don't think you want indexOfVowel to return 1 specifically under any case. You want it to do what it sounds like it will do...return the index of the first vowel in the word passed to it. If the first vowel happens to be at the beginning of the word, it will return 0, otherwise it will return a non-0 value indicating the location of the first vowel. You need that location to do the right thing elsewhere. So indexOfVowel is correct as you have it.
Your problem is your use of the substring method...understanding how to use it to pick out the right portions of the target word.
Here's a modified version of your code that does the right thing, with comments to explain the two uses of substring:
public class Test {
private static String translateWord(String word) {
int i = indexOfVowel(word);
if (i == 0) { // if word starts with vowel
return (word + "way ");
}
else { // word doesn't start with a vowel
// 'i' is the position of the first vowel
// word.substring(i) = from position of first vowel to end of word
// word.substring(0, i) = from start of word to char before first vowel
return (word.substring(i) + word.substring(0, i) + "ay ");
}
}
private static int indexOfVowel(String word) {
for (int i = 0; i < word.length(); i++) {
if (isVowel(word.charAt(i))) {
return i;
}
}
return word.length();
}
private static boolean isVowel(char ch) {
switch (ch) {
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
return true;
default:
return false;
}
}
public static void main(String[] args) {
System.out.println(translateWord("action"));
System.out.println(translateWord("translate"));
System.out.println(translateWord("parachute"));
System.out.println(translateWord("scrap"));
}
}
Result:
actionway
anslatetray
arachutepay
apscray
Example 1:
Input: S = "ab#c", T = "ad#c"
Output: true
Explanation: Both S and T become "ac".
Example 2:
Input: S = "ab##", T = "c#d#"
Output: true
Explanation: Both S and T become "".
Example 3:
Input: S = "a##c", T = "#a#c"
Output: true
Explanation: Both S and T become "c".
Example 4:
Input: S = "a#c", T = "b"
Output: false
Explanation: S becomes "c" while T becomes "b".
class Solution {
public boolean backspaceCompare(String S, String T) {
Stack<Character> stack1 = new Stack<Character>();
Stack<Character> stack2 = new Stack<Character>();
for(int i=0;i<S.length();i++){
if(S.charAt(i)!='#'){
stack1.push(S.charAt(i));
}else{
stack1.pop();
}
}
for(int j =0;j<T.length();j++){
if(T.charAt(j)!='#'){
stack2.push(S.charAt(j));
}else
stack2.pop();
}
if(stack1==stack2)
return true;
return false;
}
}
my output is false and answer should be true why is this not working?
The first mistake is pushing all the characters on the stack outside of the if statement.
Also you should check if stack is empty before removing items from it.
Otherwise EmptyStackException is thrown.
// stack1.push(S.charAt(i)); <-- remove this line
if (S.charAt(i)!='#') {
stack1.push(S.charAt(i));
}else if (!stack1.isEmpty()) { // <-- add this check
stack1.pop();
}
The second mistake is you can't use == to compare the contents of two stacks, use .equals method instead:
if(stack1.equals(stack2))
Answer by Joni correctly addresses the errors in the code, however there are some other issues I'd like to address:
You should use a helper method to eliminate repeating the same code.
You should use Deque instead of Stack. The javadoc says so.
Instead of using Stack/Deque, I'd recommend using StringBuilder, to prevent having to box the char values.
Something like this:
public boolean backspaceCompare(String s, String t) {
return applyBackspace(s).equals(applyBackspace(t));
}
private static String applyBackspace(String s) {
StringBuilder buf = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) != '#')
buf.append(s.charAt(i));
else if (buf.length() != 0)
buf.setLength(buf.length() - 1);
}
return buf.toString();
}
Your idea works, but it's expensive and unnecessary to copy the strings into stacks. If you work backwards from the end, no extra storage is necessary:
//given the string length or a valid character position, return
//the position of the previous valid character, or -1 if none
public static int previousCharPos(String s, int pos)
{
int bs=0; // number of backspaces to match
while(pos>0) {
--pos;
if (s.charAt(pos)=='#') {
++bs;
} else if (bs <= 0) {
return pos;
} else {
--bs;
}
}
return -1;
}
public static boolean backspaceCompare(String S, String T)
{
int spos = previousCharPos(S,S.length());
int tpos = previousCharPos(T,T.length());
while(spos >= 0 && tpos >= 0) {
if (S.charAt(spos) != T.charAt(tpos)) {
return false;
}
spos = previousCharPos(S,spos);
tpos = previousCharPos(T,tpos);
}
return spos == tpos;
}
I have in a class the following code...
String processor()
{
Stack<Character> stack = new Stack<>();
while (curr < infixExpr.length())
{
// assigning the current index position of string in infix expression to a variable to reduce amount of repeated code
Character element = infixExpr.charAt(curr);
if (isOperand(element))
{
postfixExpr += "" + element;
}
else if (element == '(')
{
stack.push(element);
}
else if (element == ')')
{
while (!stack.peek().equals('('))
{
postfixExpr += stack.pop(); // adding all items in stack after ( and before )
}
stack.pop(); // this should pop the stack of the waiting pushed ( paren and remove it from our postfix expression, basically ignoring it
// right paren found to trigger this else if statement was never pushed onto the stack nor assigned to the postfix expression, also ignored
}
else //*must be an operator then
{
while (OrdOpsTable.getOperatorPrecedence(stack.peek(), true) > OrdOpsTable.getOperatorPrecedence(element, false)) // flag, 'true' to signify this is from the stack. ALso, compare if it has higher precedence over the current operator
{
postfixExpr += stack.pop(); // placing found operator to end of postfix expression
}
stack.push(element);
}
curr++;
}
while (!stack.isEmpty())
{
postfixExpr += stack.pop();
}
return postfixExpr;
}
In the method "getOperatorPrecedence" parameters, I have a Stack instance called stack, calling the method peek, returning a Character Object. As the field element shows, element is of Character Object type. I created a simple flag boolean in the method parameters to make this simple.
So, the "getOperatorPrecedence" is in another class file called "OrdOpsTable"...
public final class OrdOpsTable<T> extends ArrayList
{
// INITIALIZERS
private static Character[] table = {'(','+','-','*','/','%','^'};
private static ArrayList<OperatorValues> ON_stack = new ArrayList<>();
private static ArrayList<OperatorValues> ON_curr = new ArrayList<>();
private T FROM_stack = null;
private T FROM_curr = null;
// CONSTRUCTOR
private OrdOpsTable(T curr)
{
setOperatorPrecedence();
if (curr.getClass() == Stack.class)
this.FROM_stack = curr;
else
this.FROM_curr = curr;
}
// METHODS
private static void setOperatorPrecedence()
{
// this method just sets the unique values of each operator to two arrays
int i = 0;
for (char op : table)
{
switch(op)
{
case '(':
ON_stack.add(i, new OperatorValues(op, 0));
ON_curr.add(i, new OperatorValues(op, 100));
break;
case '+':
ON_stack.add(i, new OperatorValues(op, 2));
ON_curr.add(i, new OperatorValues(op, 1));
break;
case '-':
ON_stack.add(i, new OperatorValues(op, 2));
ON_curr.add(i, new OperatorValues(op, 1));
break;
case '*':
ON_stack.add(i, new OperatorValues(op, 4));
ON_curr.add(i, new OperatorValues(op, 3));
break;
case '/':
ON_stack.add(i, new OperatorValues(op, 4));
ON_curr.add(i, new OperatorValues(op, 3));
break;
case '%':
ON_stack.add(i, new OperatorValues(op, 4));
ON_curr.add(i, new OperatorValues(op, 3));
break;
case '^':
ON_stack.add(i, new OperatorValues(op, 5));
ON_curr.add(i, new OperatorValues(op, 6));
break;
}
i++;
}
}
public static int getOperatorPrecedence(Object curr, boolean FROM_stack)
{
setOperatorPrecedence();
if (FROM_stack)
{
return ON_stack.get(ON_stack.indexOf(curr)).value;
}
else
{
return ON_curr.get(ON_stack.indexOf(curr)).value;
}
}
/* SUBCLASS */
private static class OperatorValues
{
// FIELDS
private char operator;
private int value;
// CONSTRUCTOR
OperatorValues(char operator, int value)
{
this.operator = operator;
this.value = value;
}
// METHOD
char getOperator()
{
return this.operator;
}
int getValue()
{
return this.value;
}
public String toString()
{
return this.operator;
}
}
What I need help with is finding a way to correctly return the OperatorValue subclass field value for both instances of
return ON_stack.get(ON_stack.indexOf(curr)).value;
and
return ON_curr.get(ON_stack.indexOf(curr)).value;
I'm getting the following error...
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
at java.util.ArrayList.elementData(ArrayList.java:418)
at java.util.ArrayList.get(ArrayList.java:431)
at OrdOpsTable.getOperatorPrecedence(OrdOpsTable.java:79)
at PostfixParser.processor(PostfixParser.java:57)
at InfixPostfixTester.main(InfixPostfixTester.java:78)
It appears when I debug and follow this, the issue is in "Character" class "equals". First, when I force step into the first return statement in question, it goes to the indexOf() in ArrayList...
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
When the debugger hits the .equals method in here, it goes into the Character class...
public boolean equals(Object obj) {
if (obj instanceof Character) {
return value == ((Character)obj).charValue();
}
return false;
}
The issue here is that the IF statement in this equals method is failing at this comparison. It seems it's comparing obj as my custom made OperatorValues class's toString() and it is obviously not an instanceof a Character class. So, it's failing because it's comparing "(" as a Character. I need it to compare '(' to trigger 'true' in this method.
For an example, I assigned the char '(' with an int of '0' in one array and '100' in another array as you can see above in my OrdOpsTable class in the method setOperatorPrecedence(). When the Character class equals() method is called here without using OperatorValues class's toString(), my debugger says the inline value for curr's '(' in this equal method shows, "obj: OrdOpsTable$OperatorValues#636.
If there was a way to make my toString() method in OperatorValues return a Character instead of String. This of course would cause an error if I did so. Any suggestions on what you would do here?
*NOTE: Let me know if I need to provide more info for you. This is a homework assignment from a class, I've spent alot of time stuck on this part and I've tried relentlessly. I need some outsourcing help to understand what I'm missing.
I figured it out, I changed everything that was of Character class to String class and in my OrdOpsTable class, getOperatorPrecedence() method, to force the comparison from its native class of my custom OperatorValues class to String class, I did this...
return ON_stack.get(ON_stack.toString().indexOf(curr)).getValue();
Thanks everyone who did pitch in for the help, appreciate it.
So here's what I'm trying to accomplish. I'm trying to make a code that does the following from 2 given Strings: a target and a source.
// Determines whether the string TARGET occurs as a substring of string SOURCE where "gaps" are allowed between characters of target.`
// That is, the characters in TARGET occur in SOURCE in their given order but do not have to be adjacent.`
// (Pictured another way, this method returns true if TARGET could be obtained from SOURCE by removing some of the letters of SOURCE.)`
// This method is case sensitive. For example,`
// containsWithGaps("hamburgers", "mug") returns true`
// containsWithGaps("hamburgers", "burrs") returns true`
// containsWithGaps("hamburgers", "hamburgers") returns true`
// containsWithGaps("hamburgers", "gum") returns false`
// containsWithGaps("hamburgers", "hamm") returns false`
// containsWithGaps("hamburgers", "") returns true`
// Parameters:`
// SOURCE - the given string in which to find the target characters`
// TARGET - the characters to be found`
// Returns:`
// true if the characters in TARGET can be found as a subsequence in SOURCE, false otherwise`
And here's the code I've written. It seems to be overly complicated for what I believe shouldn't be a difficult task, but no matter what, I still keep getting errors and it won't work if given a SOURCE string hamburgers with a TARGET string burr:
public static boolean substringWithGaps(String source, String target) {
boolean substring = false;
int[] target_index;
target_index = new int [target.length()];
if (target.length() > source.length()) {
substring = false;
}
else {
for (int i = 0; i < target.length(); i++) {
if (source.contains("" + target.charAt(i))) {
target_index[i] = target.indexOf(i);
i++;
}
else {
target_index[i] = target.indexOf(i);
i++;
}
}
for (int i = 0; i < target_index.length; i++) {
if (target_index[i] == -1) {
substring = false;
break;
}
else if (target_index[i] >= target_index[i+1]) {
substring = false;
break;
}
else {
substring = true;
}
if (target_index.length != target.length()) {
substring = false;
}
}
}
return substring;
}
Any ideas?
Should be pretty simple:
public static boolean substringWithGaps(String source, String target) {
int targetIndex = 0;
for (int i = 0; i < source.length(); i++) {
if (source.charAt(i) == target.charAt(targetIndex)) {
targetIndex = targetIndex + 1;
if (targetIndex == target.length()) {
return true;
}
}
}
return false;
}
We keep an index of the next letter we need to find within target. Then we loop over source looking for that letter, and when we find it we move the index within target forward one. If the index of target ever equals the length of target, that means we found all of the characters we needed. If we loop over all of source without finding all of target, we return false.
The following should do it.
public static boolean containsWithGaps(String a, String b){
if(b.length() > a.length())
{
return false;
}
char[] targetChars = new char[b.length()];
b.getChars(0,b.length(),targetChars, 0);
int pos = 0;
for(char myChar : targetChars)
{
pos = a.indexOf(myChar, pos);
if(pos == -1)
{
return false;
}
}
return true;
}
Slight optimization in that it returns as soon as a character could not be matched (and doesn't crash if target is zero length)
public static boolean substringWithGaps(String source, String target) {
for (int i = 0, last = -1; i < target.length(); i++) {
if (-1 == (last = source.indexOf(target.charAt(i), last + 1)))
return false;
}
return true;
}
package edu.bsu.cs121.mamurphy;
import java.util.Stack;
public class Checker {
char openPara = '(';
char openBracket = '[';
char openCurly = '{';
char openArrow = '<';
char closePara = ')';
char closeBracket = ']';
char closeCurly = '}';
char closeArrow = '>';
public boolean checkString(String stringToCheck) {
Stack<Character> stack = new Stack<Character>();
for (int i = 0; i < stringToCheck.length(); i++) {
char c = stringToCheck.charAt(i);
if (c == openPara || c == openBracket || c == openCurly || c == openArrow) {
stack.push(c);
System.out.println(stack);
;
}
if (c == closePara) {
if (stack.isEmpty()) {
System.out.println("Unbalanced");
break;
} else if (stack.peek() == openPara) {
stack.pop();
} else if (stack.size() > 0) {
System.out.println("Unbalanced");
break;
}
}
if (c == closeBracket) {
if (stack.isEmpty()) {
System.out.println("Unbalanced");
break;
} else if (stack.peek() == openBracket) {
stack.pop();
} else if (stack.size() > 0) {
System.out.println("Unbalanced");
break;
}
}
if (c == closeCurly) {
if (stack.isEmpty()) {
System.out.println("Unbalanced");
break;
} else if (stack.peek() == openCurly) {
stack.pop();
} else if (stack.size() > 0) {
System.out.println("Unbalanced");
break;
}
}
if (c == closeArrow) {
if (stack.isEmpty()) {
System.out.println("Unbalanced");
break;
} else if (stack.peek() == openArrow) {
stack.pop();
} else if (stack.size() > 0) {
System.out.println("Unbalanced");
break;
}
}
}
return false;
}
}
I am currently trying to create a program where I check to see if a string is balanced or not. A string is balanced if and only if each opening character: (, {, [, and < have a matching closing character: ), }, ], and > respectively.
What happens is when checking through the string, if an opening character is found, it is pushed into a stack, and it checks to see if there is the appropriate closing character.
If there is a closing character before the opening character, then that automatically means that the string is unbalanced. Also, the string is automatically unbalanced if after going to the next character there is something still inside of the stack.
I tried to use
else if (stack.size() > 0) {
System.out.println("Unbalanced");
break;
}
as a way of seeing if the stack still had anything in it, but it still isn't working for me. Any advice on what to do?
For example, if the string input were ()<>{() then the program should run through like normal until it gets to the single { and then the code should realize that the string is unbalanced and output Unbalanced.
For whatever reason, my code does not do this.
The following logic is flawed (emphasis mine):
For example, if the string input were ()<>{() then the program should run through like normal until it gets to the single { and then the code should realize that the string is unbalanced and output Unbalanced.
In fact, the code can't conclude that the string is unbalanced until it has scanned the entire string and established that the { has no matching }. For all it knows, the full input could be ()<>{()} and be balanced.
To achieve this, you need to add a check that ensures that the stack is empty after the entire string has been processes. In your example, it would still contain the {, indicating that the input is not balanced.
I took a shot at answering this. My solutions returns true if the string is balanced and enforces opening/closing order (ie ({)} returns false). I started with your code and tried to slim it down.
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
public class mamurphy {
private static final char openPara = '(';
private static final char openBracket = '[';
private static final char openCurly = '{';
private static final char openArrow = '<';
private static final char closePara = ')';
private static final char closeBracket = ']';
private static final char closeCurly = '}';
private static final char closeArrow = '>';
public static void main(String... args) {
System.out.println(checkString("{}[]()90<>"));//true
System.out.println(checkString("(((((())))"));//false
System.out.println(checkString("((())))"));//false
System.out.println(checkString(">"));//false
System.out.println(checkString("["));//false
System.out.println(checkString("{[(<>)]}"));//true
System.out.println(checkString("{[(<>)}]"));//false
System.out.println(checkString("( a(b) (c) (d(e(f)g)h) I (j<k>l)m)"));//true
}
public static boolean checkString(String stringToCheck) {
final Map<Character, Character> closeToOpenMap = new HashMap<>();
closeToOpenMap.put(closePara, openPara);
closeToOpenMap.put(closeBracket, openBracket);
closeToOpenMap.put(closeCurly, openCurly);
closeToOpenMap.put(closeArrow, openArrow);
Stack<Character> stack = new Stack<>();
final char[] stringAsChars = stringToCheck.toCharArray();
for (int i = 0; i < stringAsChars.length; i++) {
final char current = stringAsChars[i];
if (closeToOpenMap.values().contains(current)) {
stack.push(current); //found an opening char, push it!
} else if (closeToOpenMap.containsKey(current)) {
if (stack.isEmpty() || closeToOpenMap.get(current) != stack.pop()) {
return false;//found closing char without correct opening char on top of stack
}
}
}
if (!stack.isEmpty()) {
return false;//still have opening chars after consuming whole string
}
return true;
}
}
Here's an alternate approach:
private static final char[] openParens = "[({<".toCharArray();
private static final char[] closeParens = "])}>".toCharArray();
public static boolean isBalanced(String expression){
Deque<Character> stack = new ArrayDeque<>();
for (char c : expression.toCharArray()){
for (int i = 0; i < openParens.length; i++){
if (openParens[i] == c){
// This is an open - put it in the stack
stack.push(c);
break;
}
if (closeParens[i] == c){
// This is a close - check the open is at the top of the stack
if (stack.poll() != openParens[i]){
return false;
}
break;
}
}
}
return stack.isEmpty();
}
It simplifies the logic to have two corresponding arrays of open and close symbols. You could also do this with even and odd positions in one array - ie. "{}<>", for example:
private static final char[] symbols = "[](){}<>".toCharArray();
public static boolean isBalanced(String expression){
Deque<Character> stack = new ArrayDeque<>();
for (char c : expression.toCharArray()){
for (int i = 0; i < symbols.length; i += 2){
if (symbols[i] == c){
// This is an open - put it in the stack
stack.push(c);
break;
}
if (symbols[i + 1] == c){
// This is a close - check the open is at the top of the stack
if (stack.poll() != symbols[i]){
return false;
}
break;
}
}
}
return stack.isEmpty();
}
Note that poll returns null if the stack is empty, so will correctly fail the equality comparison if we run out of stack.
For example, if the string input were ()<>{() then the program should run through like normal until it gets to the single { and then the code should realize that the string is unbalanced and output Unbalanced.
It is not clear by your example whether the boundaries can be nested like ([{}]). If they can, that logic will not work, as the whole string has to be consumed to be sure any missing closing-chars aren't at the end, and so, the string cannot be reliably deemed unbalanced at the point you indicate.
Here is my take on your problem:
BalanceChecker class:
package so_q33378870;
import java.util.Stack;
public class BalanceChecker {
private final char[] opChars = "([{<".toCharArray();
private final char[] edChars = ")]}>".toCharArray();
//<editor-fold defaultstate="collapsed" desc="support functions">
public boolean isOPChar(char c) {
for (char checkChar : opChars) {
if (c == checkChar) {
return true;
}
}
return false;
}
public boolean isEDChar(char c) {
for (char checkChar : edChars) {
if (c == checkChar) {
return true;
}
}
return false;
}
//NOTE: Unused.
// public boolean isBoundaryChar(char c) {
// boolean result;
// if (result = isOPChar(c) == false) {
// return isEDChar(c);
// } else {
// return result;
// }
// }
public char getOpCharFor(char c) {
for (int i = 0; i < edChars.length; i++) {
if (c == edChars[i]) {
return opChars[i];
}
}
throw new IllegalArgumentException("The character (" + c + ") received is not recognized as a closing boundary character.");
}
//</editor-fold>
public boolean isBalanced(char[] charsToCheck) {
Stack<Character> checkStack = new Stack<>();
for (int i = 0; i < charsToCheck.length; i++) {
if (isOPChar(charsToCheck[i])) {
//beginning char found. Add to top of stack.
checkStack.push(charsToCheck[i]);
} else if (isEDChar(charsToCheck[i])) {
if (checkStack.isEmpty()) {
//ending char found without beginning chars on the stack. UNBALANCED.
return false;
} else if (getOpCharFor(charsToCheck[i]) == checkStack.peek()) {
//ending char found matches last beginning char on the stack. Pop and continue.
checkStack.pop();
} else {
//ending char found, but doesn't match last beginning char on the stack. UNBALANCED.
return false;
}
}
}
//the string is balanced if and only if the stack is empty at the end.
return checkStack.empty();
}
public boolean isBalanced(String stringToCheck) {
return isBalanced(stringToCheck.toCharArray());
}
}
Main class (used for testing):
package so_q33378870;
public class main {
private static final String[] tests = {
//Single - Balanced.
"()",
//Single - Unbalanced by missing end.
"(_",
//Multiple - Balanced.
"()[]{}<>",
//Multiple - Unbalanced by missing beginning.
"()[]_}<>",
//Nested - Balanced.
"([{<>}])",
//Nested - Unbalanced by missing end.
"([{<>}_)",
//Endurance test - Balanced.
"the_beginning (abcd) divider (a[bc]d) divider (a[b{c}d]e) divider (a[b{c<d>e}f]g) the_end"
};
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
BalanceChecker checker = new BalanceChecker();
for (String s : tests) {
System.out.println("\"" + s + "\" is " + ((checker.isBalanced(s)) ? "BALANCED!" : "UNBALANCED!"));
}
}
}