《啊哈!算法》第二章 - 第二节 - 解密回文 - 栈(Java实现)
上一节学习了队列, 队列是一种先进先出的数据结构。还有一种是 后进先出的数据结构,它叫做栈。 栈限定为只能在一端进行插入和删除操作。
比如说有一个小桶,小桶的直径只能放一个小球,要在小桶内依次放入 2、1、3号小球。假如现在需要拿出 2号小球, 那就必须先将 3号小球拿出,再拿出 1号小球,之后才能将2号小球拿出来。在刚才取小球的过程中,先放进去的小球最后才能拿出来,最后放进去的小球却可以先拿出来。
题目1:判断回文字符串
回文字符串就是指正读反读均相同的字符序列,如 “ 席主席 ”、“ 记书记 ”、“ aha ” 和 “ ahaha ” 均是回 文,但 “ ahah ” 不是回文。要求使用算法来判断一个给定字符串是否为回文字符串
解题思路:
如果一个字符串是回文的话,那么它必须是中间对称的。我们需要求字符串的中间点,然后将中间点以前的字符串反过来与中间点后面的字符串一一比较,如果都相等,则给定的字符串是回文字符串。但是如何怎么样才能将给定字符串的中间点前面的字符串依次读入然后再反过来读出呢?还记得栈的特性——后进先出吗?
栈的实现也很简单,只需要一个一维数组和一个指向栈顶的指针(变量)top,这样在插入或者删除栈中数据时只需要移动 top 指针就行了,通过栈这个数据结构将很容易判断一个字符串是否为回文。
代码实现:
import java.util.Scanner;
public class T2 {
public static void main(String[] args) {
// 回文(栈)
System.out.println("请输入要判断的回文字符串:");
Scanner sc1 = new Scanner(System.in);
String str = sc1.nextLine();
char cha[] = str.toCharArray();
System.out.println("请输入要判断的回文字符串的长度:");
Scanner sc2 = new Scanner(System.in);
int n = sc2.nextInt();
// 使用数组模拟栈
char stack[] = new char[n];
// 求回文字符串的中点
int len = str.length();
int mid = len/2;
// 将 mid 之前的回文字符串入栈
int top = 0;
for(int i = 0; i < mid; i++) {
stack[top] = cha[i];
top++;
}
// 判断字符串长度是奇数还是偶数,并决定需要匹配的字符串的开始下标
int next = 0;
if(len % 2 == 0) {
next = mid;
}else {
next = mid+1;
}
// 也可以换成下列判断语句
// int next = (len & 1) == 0 ? mid : (mid + 1);
// 问号前面的表达式为 true,返回冒号左边的,false 返回冒号右边的
// 在 java 中,非 0 为 true
// len 如果为 0 或 null,就为 false
// 将栈内的字符串出栈与 mid 之后的字符串一一判断是否相等
for(int i = next; i < len; i++) {
if(cha[i] != stack[top-1]) { // stack的下标是从0开始的,top需要减1才能指向需要指向的字符
break;
}else {
top--;
}
}
// 如果所有的字符串都被匹配,top=0,说明该字符串是回文字符串,否则该字符串不是回文字符串
if(top == 0) {
System.out.println("该字符串是回文字符串");
}else {
System.out.println("该字符串不是回文字符串");
}
}
}
运行结果:
栈还可以用来进行验证括号的匹配。
题目2:括号匹配
请判断给定的括号字符串是否可以正确匹配
例如: ()、[ ] 、{ }、<> 这些括号是对应匹配的
解题思路:
解题思路和判断回文字符串是一样的,但是在最后的判断条件上进行了改动,按照括号进行匹配。
代码实现:
import java.util.Scanner;
public class T4 {
public static void main(String[] args) {
// 括号匹配
System.out.println("请输入要判断的括号字符串:");
Scanner sc1 = new Scanner(System.in);
String str = sc1.nextLine();
char cha[] = str.toCharArray();
System.out.println("请输入要判断的括号字符串的长度:");
Scanner sc2 = new Scanner(System.in);
int n = sc2.nextInt();
// 使用数组模拟栈
char stack[] = new char[n];
// 求回文字符串的中点
int len = str.length();
int mid = len/2;
// 将 mid 之前的回文字符串入栈
int top = 0;
for(int i = 0; i < mid; i++) {
stack[top] = cha[i];
top++;
}
// 判断字符串长度是奇数还是偶数,并决定需要匹配的字符串的开始下标
int next = 0;
if(len % 2 == 0) {
next = mid;
}else {
next = mid+1;
}
// 也可以换成下列判断语句
// int next = (len & 1) == 0 ? mid : (mid + 1);
// 问号前面的表达式为 true,返回冒号左边的,false 返回冒号右边的
// 在 java 中,非 0 为 true
// len 如果为 0 或 null,就为 false
// 将栈内的字符串出栈与 mid 之后的字符串一一判断是否相等
for(int i = next; i < len; i++) {
if((cha[i] == '(' && stack[top-1] == ')') ||
(cha[i] == ')' && stack[top-1] == '(')) { // stack的下标是从0开始的,top需要减1才能指向需要指向的字符
top--;
}else if((cha[i] == '{' && stack[top-1] == '}') ||
(cha[i] == '}' && stack[top-1] == '{')) {
top--;
}else if((cha[i] == '[' && stack[top-1] == ']') ||
(cha[i] == ']' && stack[top-1] == '[')) {
top--;
}else if((cha[i] == '<' && stack[top-1] == '>') ||
(cha[i] == '>' && stack[top-1] == '<')) {
top--;
}else {
break;
}
}
// 如果所有的字符都被匹配,top=0,说明该括号字符串是回文字符串,否则该括号字符串不是回文字符串
if(top == 0) {
System.out.println("该括号字符串是回文字符串");
}else {
System.out.println("该括号字符串不是回文字符串");
}
}
}
运行结果:
总结
1、栈的特性:后进先出(Last In First Out, LIFO)
2、栈的实现:一个一维数组和一个变量 top 封装起来就行了
3、出栈、入栈的操作:移动栈顶指针(即变量 top)
4、空栈:当变量 top 的值等于0时,则说明当前栈是一个空栈。
堆栈的概念最早由Alan M.Turing(艾伦·图灵)提出的,意在解决子程序的调用和返回。