给定一个只包括 '('
,')'
,'{'
,'}'
,'['
,']'
的字符串,判断字符串是否有效。
有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
示例 1:
输入: "()" 输出: true
示例 2:
输入: "()[]{}" 输出: true
示例 3:
输入: "(]" 输出: false
示例 4:
输入: "([)]" 输出: false
示例 5:
输入: "{[]}" 输出: true
tip:栈的典型的应用,括号的配对。
思路分析:
首先,我们可以将两种特殊的情况直接排除,即当输入的字符串为null或长度为0时,我们可以直接返回true;当输入的字符串的长度为奇数时,则直接返回false。排除了这两种情况之后,我们可以通过栈这种数据结构来帮助我处理这个问题。我们可以从字符串的第一个字符开始逐一遍历,若为"左边"括号,则将这个字符压栈。若为"右边"括号,则判断栈是否为空,若为空,则返回false。否则将栈顶元素出栈,判断这个栈顶元素的括号是否与这个"右边"括号匹配,若匹配则继续遍历下个字符,否则则直接返回false。当所有的字符都遍历完成,栈为空,则返回true,否则说明还有括号未配对,则返回false。既然思路已经理清了。我们就可以顺着这个思路来完成代码了。
代码实现:
public static boolean isValid(String s) {
if (s == null || s.length() == 0) { //s为空或长度为0
return true;
}
if (s.length() % 2 != 0) { //s的长度为奇数
return false;
}
// 构建对应关系
Map<Character, Character> map = new HashMap<Character, Character>();
map.put('(', ')');
map.put('[', ']');
map.put('{', '}');
Stack<Character> stack = new Stack<Character>(); // 创建栈
char[] chars = s.toCharArray(); // 获得字符串的每个字符
if (chars[0] == ')' || chars[0] == ']' || chars[0] == '}') { // 若第一个字符为"右边"括号,则false
return false;
} else { // 否则将第一个压栈
stack.push(chars[0]);
}
for (int i = 1; i < chars.length; i++) { // 从第二个字符开始遍历数组
if (chars[i] == '(' || chars[i] == '[' || chars[i] == '{') { // 若字符为"左边"括号,则压栈
stack.push(chars[i]);
} else { // 否则对chars[i]与栈顶元素进行判断是否匹配
if (stack.isEmpty()) { //若栈为空
if (chars[i] == ')' || chars[i] == ']' || chars[i] == '}') {
return false;
} else { //为"左边"括号,则压栈
stack.push(chars[i]);
continue;
}
}
char ch = stack.pop(); // 弹出栈顶元素
char want = map.get(ch); // 通过map查看期待的匹配符号
if (want != chars[i]) { // 若chars[i]不为期待符号,则false
return false;
}
}
}
if (stack.isEmpty()) { //若最后栈为空,即所有元素都匹配成功
return true;
}
else{
return false;
}
}
代码优化:
我们第一次代码借助了栈这种数据结构来帮助我们完成,我们可以试着想想,能不能不借助栈,就能完成同样的工作呢?这当然是可以的,我们可以模仿着栈,定义一个光标cur来指向"栈顶元素"。这样我们就实现了类似于栈的结构,而并没有真正的用到栈,这样程序的执行效率就提高了不少。
public static boolean isValid(String s) {
char[] chs=s.toCharArray(); //获取字符数组
int cur=0; //定义光标位置
for(int i=0;i<s.length();i++){ //从一个字符开始
char c=s.charAt(i);
switch (c){
case '(': //若为"左边"括号,则光标向右移动一个位置
case '[':
case '{':chs[cur++]=c; break;
//分别对右边括号进行匹配
case ')':
if(cur==0) //若栈为空
return false;
char c1=chs[--cur]; //获取"栈顶元素"
if(c1!='(')
return false;
break;
case ']':
if(cur==0)
return false;
char c2=chs[--cur];
if(c2!='[')
return false;
break;
case '}':
if(cur==0)
return false;
char c3=chs[--cur];
if(c3!='{')
return false;
break;
}
}
if(cur!=0){ //若最后光标不为0,则还有未匹配的括号
return false;
}
return true;
}