一、用栈访问最后若干元素
question 682(棒球)、
answer
class Solution {
public int calPoints(String[] ops) {
int res=0;
int[] arr=new int[ops.length];
int i=0;
for(String s:ops){
switch(s){
case "+" : arr[i]=arr[i-1]+arr[i-2];i++; break;
case "D" : arr[i]=2*arr[i-1];i++;break;
case "C" : arr[i-1]=0;i--;break;
default : arr[i]=Integer.valueOf(s);i++;
}
}
for(int num:arr){
res+=num;
}
return res;
}
}
question71(简化路径)、
answer
class Solution {
public String simplifyPath(String path) {
String[] names=path.split("/");
//java官方推荐栈用双端队列
Deque<String> stack=new ArrayDeque<String>();
for(String name:names){
if("..".equals(name)){
if(!stack.isEmpty()){
stack.pollLast();
}
}else if(name.length()>0&&!".".equals(name)){
stack.offerLast(name);
}
}
StringBuffer ans=new StringBuffer();
if(stack.isEmpty()){
ans.append("/");
}else{
while(!stack.isEmpty()){
ans.append("/");
ans.append(stack.pollFirst());
}
}
return ans.toString();
}
}
question 388(文件的最长绝对路径)
answer
class Solution {
public int lengthLongestPath(String input) {
int n = input.length();
//下标
int pos = 0;
//ans记录当前最长的路径
int ans = 0;
Deque<Integer> stack = new ArrayDeque<Integer>();
while (pos < n) {
/* 检测当前文件(一个文件夹)的深度 */
int depth = 1;
//第几级目录就有几个'\t'
while (pos < n && input.charAt(pos) == '\t') {
pos++;
depth++;
}
/* 统计当前文件名的长度 */
boolean isFile = false;
int len = 0;
while (pos < n && input.charAt(pos) != '\n') {
if (input.charAt(pos) == '.') {
isFile = true;
}
len++;
pos++;
}
/* 跳过当前的换行符 */
pos++;
//stack.size()应该小于depth,才属于同一级目录,此刻还未插入当前文件长度
while (stack.size() >= depth) {
stack.pop();
}
//加一是 ’/‘
if (!stack.isEmpty()) {
len += stack.peek() + 1;
}
if (isFile) {
ans = Math.max(ans, len);
} else {
//文件长度递增的入栈(l1,l2+l1+1,l1+l2+l3+2)
stack.push(len);
}
}
return ans;
}
}
二、栈与计算器
question 150(逆波兰表达式求值)、
answer
class Solution {
public int evalRPN(String[] tokens) {
int len=tokens.length;
Deque<Integer> stack=new ArrayDeque<>();
String operaters="+-*/";
for(int i=0;i<len;i++){
String token=tokens[i];
if(!operaters.contains(token)){
//push 添加栈顶
stack.push(Integer.parseInt(token));
}else{
//pop移除栈顶
int num1=stack.pop();
int num2=stack.pop();
switch(token){
case "+" : stack.push(num1+num2);break;
case "-" : stack.push(num2-num1);break;
case "*" : stack.push(num1*num2);break;
case "/" : stack.push(num2/num1);break;
}
}
}
return stack.pop();
}
}
answer2
class Solution {
public int evalRPN(String[] tokens) {
int len=tokens.length;
Deque<Integer> stack=new ArrayDeque<>();
for(int i=0;i<len;i++){
String token=tokens[i];
if(isNumber(token)){
//push 添加栈顶
stack.push(Integer.parseInt(token));
}else{
//pop移除栈顶
int num1=stack.pop();
int num2=stack.pop();
switch(token){
case "+" : stack.push(num1+num2);break;
case "-" : stack.push(num2-num1);break;
case "*" : stack.push(num1*num2);break;
case "/" : stack.push(num2/num1);break;
}
}
}
return stack.pop();
}
public boolean isNumber(String token) {
return !("+".equals(token) || "-".equals(token) || "*".equals(token) || "/".equals(token));
}
}
question 227(基本计算器)、
answer
class Solution {
//一般需要两个栈,一个数据栈,一个符号栈
//符号栈用sign代替,只存储上一个符号,乘除直接计算,减变加负数
public int calculate(String s) {
//-2 = +(-2)
//保存上一个符号,初始为+
char sign='+';
//当前数
int num=0;
Deque<Integer> stack=new LinkedList<>();
int len=s.length();
for(int i=0;i<len;i++){
if(Character.isDigit(s.charAt(i))){
//可能存在进位的情况
num=num*10+s.charAt(i)-'0';
}
if(!Character.isDigit(s.charAt(i))&&s.charAt(i)!=' '||i==len-1){
switch(sign){
//push从头插入
case '+' : stack.push(num);break;
case '-' : stack.push(-num);break;
case '*' : stack.push(stack.pop()*num); break;
case '/' : stack.push(stack.pop()/num); break;
}
sign=s.charAt(i);
num=0;
}
}
//处理stack里面相加的数字
int ans=0;
while(!stack.isEmpty()){
ans+=stack.pop();
}
return ans;
}
}
question224(基本计算器)
answer
class Solution {
public int calculate(String s) {
Deque<Integer> stack=new LinkedList<>();
//sign 代表正负
int sign=1;
int res=0;
int length=s.length();
for(int i=0;i<length;i++){
char ch=s.charAt(i);
if(Character.isDigit(ch)){
int cur=ch-'0';
//可能不是个位数
while(i+1<length&&Character.isDigit(s.charAt(i+1))){
cur=cur*10+s.charAt(++i)-'0';
}
//没遇到括号,直接累加
res=res+cur*sign;
}else if(ch=='+'){
sign=1;
}else if(ch=='-'){
sign=-1;
}else if(ch=='('){
//括号外面已经累加的数,入栈
stack.push(res);
res=0;
stack.push(sign);
sign=1;
}else if(ch==')'){
//res*stack.pop(),弹出的是符号位
res=res*stack.pop()+stack.pop();
}
}
return res;
}
}
三、栈与括号匹配
question20(有效的括号)、
answer
class Solution {
public boolean isValid(String s) {
int len=s.length();
if(len%2!=0){
return false;
}
Map<Character,Character> pairs=new HashMap<>();
pairs.put(')','(');
pairs.put(']','[');
pairs.put('}','{');
//遇到左括号,入栈,遇到右括号,看栈中是否有对应的左括号
Deque<Character> stack=new LinkedList<>();
for(int i=0;i<len;i++){
char cur=s.charAt(i);
//如果是右括号
if(pairs.containsKey(cur)){
if(stack.isEmpty()||stack.peek()!=pairs.get(cur)){
return false;
}
stack.pop();
}else{
stack.push(cur);
}
}
return stack.isEmpty();
}
}
answer 2
时间复杂度高,replace o(n)
class Solution {
public boolean isValid(String s) {
if(s.length()%2!=0){
return false;
}
int len=s.length()/2;
for(int i=0;i<len;i++){
s=s.replace("()","");
s=s.replace("[]","");
s=s.replace("{}","");
if(s.length()==0){
return true;
}
}
return false;
}
}
question636(函数的独占时间)、
answer
class Solution {
public int[] exclusiveTime(int n, List<String> logs) {
//这道题关键是单线程非抢占cpu,就是说父函数调用子函数
//子函数结束之后、父函数才有可能结束。不会出现父函数结束了,子函数继续运行的情况。
//即只有最内层的进程出战后,外层进程才可能出栈
//遇到start入栈,end出栈
//最内层函数出栈后要判断栈顶是否还有函数,有的话,下一个出栈的就是,要把当前函数的占用时间减掉
Deque<int[]> stack=new LinkedList<>();
//n个程序
int[] res =new int[n];
for(String log:logs){
//把每一项用 : 分割开
String[] s=log.split(":");
int id=Integer.parseInt(s[0]);
int time=Integer.parseInt(s[2]);
//如果是开始时间就入栈
if("start".equals(s[1])){
stack.push(new int[]{id,time});
//如果是结束时间就统计当前id运行的时间
}else if("end".equals(s[1])){
//0:id, 1:time
int[] pop=stack.pop();
//运行时间=end-start+1;
int interval=time-pop[1]+1;
//把当前id的运行时间存储起来
res[pop[0]]+=interval;
//下一个进程减去当前运行的时间
if(!stack.isEmpty()){
res[stack.peek()[0]]-=interval;
}
}
}
return res;
}
}
question591(标签验证器)*、
answer
answer
class Solution {
public boolean isValid(String code) {
int n = code.length();
Deque<String> tags = new ArrayDeque<String>();
int i = 0;
while (i < n) {
if (code.charAt(i) == '<') {
if (i == n - 1) {
return false;
}
//如果遇到结束符
if (code.charAt(i + 1) == '/') {
//结束符的位置
int j = code.indexOf('>', i);
if (j < 0) {
return false;
}
//截取结束符的名字
String tagname = code.substring(i + 2, j);
//与开始符名字比较 是否相等
if (tags.isEmpty() || !tags.peek().equals(tagname)) {
return false;
}
tags.pop();
i = j + 1;
if (tags.isEmpty() && i != n) {
return false;
}
} else if (code.charAt(i + 1) == '!') {
//如果是[CDATA[
if (tags.isEmpty()) {
return false;
}
// i+9是cdate里面的内容
if (i + 9 > n-1) {
return false;
}
String cdata = code.substring(i + 2, i + 9);
if (!"[CDATA[".equals(cdata)) {
return false;
}
int j = code.indexOf("]]>", i);
if (j < 0) {
return false;
}
//跳过]]>
i = j + 3;
} else {
int j = code.indexOf('>', i);
if (j < 0) {
return false;
}
String tagname = code.substring(i + 1, j);
if (tagname.length() < 1 || tagname.length() > 9) {
return false;
}
for (int k = 0; k < tagname.length(); ++k) {
if (!Character.isUpperCase(tagname.charAt(k))) {
return false;
}
}
tags.push(tagname);
i = j + 1;
}
} else {
if (tags.isEmpty()) {
return false;
}
++i;
}
}
return tags.isEmpty();
}
}
question32(最长有效括号)
answer
class Solution {
public int longestValidParentheses(String s) {
int res=0;
Deque<Integer> stack=new LinkedList<Integer>();
//表示最后一个没有被匹配的右括号的下标
stack.push(-1);
for(int i=0;i<s.length();i++){
if(s.charAt(i)=='('){
stack.push(i);
}else{
stack.pop();
if(stack.isEmpty()){
//没有左括号匹配,更新最后一个没有被匹配的右括号下标
stack.push(i);
}else{
//匹配
res=Math.max(res,i-stack.peek());
}
}
}
return res;
}
}
四、递归
question 385(迷你语法分析器)、
answer
/**
* // This is the interface that allows for creating nested lists.
* // You should not implement it, or speculate about its implementation
* public interface NestedInteger {
* // Constructor initializes an empty nested list.
* public NestedInteger();
*
* // Constructor initializes a single integer.
* public NestedInteger(int value);
*
* // @return true if this NestedInteger holds a single integer, rather than a nested list.
* public boolean isInteger();
*
* // @return the single integer that this NestedInteger holds, if it holds a single integer
* // Return null if this NestedInteger holds a nested list
* public Integer getInteger();
*
* // Set this NestedInteger to hold a single integer.
* public void setInteger(int value);
*
* // Set this NestedInteger to hold a nested list and adds a nested integer to it.
* public void add(NestedInteger ni);
*
* // @return the nested list that this NestedInteger holds, if it holds a nested list
* // Return empty list if this NestedInteger holds a single integer
* public List<NestedInteger> getList();
* }
*/
class Solution {
//用栈做
public NestedInteger deserialize(String s) {
if(s.charAt(0)!='['){
return new NestedInteger(Integer.parseInt(s));
}
Deque<NestedInteger> stack=new ArrayDeque<>();
int num=0;
int flage=1;
for(int i=0;i<s.length();i++){
char c=s.charAt(i);
if(c=='-'){
flage=-1;
}else if(Character.isDigit(c)){
num=num*10+c-'0';
}else if(c=='['){
stack.push(new NestedInteger());
}else if(c==','||c==']'){
if(Character.isDigit(s.charAt(i-1))){
num*=flage;
stack.peek().add(new NestedInteger(num));
}
num=0;
flage=1;
if(c==']'&&stack.size()>1){
NestedInteger ni=stack.pop();
stack.peek().add(ni);
}
}
}
return stack.pop();
}
}
question341 *、
question 394(字符串解码)
answer
class Solution {
/**
* 双栈解法:
* 准备两个栈,一个存放数字,一个存放字符串
* 遍历字符串分4中情况
* 一、如果是数字 将字符转成整型数字 注意数字不一定是个位 有可能是十位,百位等
所以digit = digit*10 + ch - '0';
* 二、如果是字符 直接将字符放在临时字符串中
* 三、如果是"[" 将临时数字和临时字符串入栈
* 四、如果是"]" 将数字和字符串出栈 此时临时字符串res = 出栈字符串 + 出栈数字*res
*/
public String decodeString(String s) {
//创建数字栈,创建字符串栈及临时数字和临时字符串
Deque<Integer> stack_digit=new LinkedList<>();
Deque<StringBuilder> stack_string=new LinkedList<>();
int digit=0;
StringBuilder res=new StringBuilder();
//遍历字符串分4中情况
for(int i=0;i<s.length();i++){
char ch=s.charAt(i);
if(ch=='['){
//如果是"["将临时数字和临时字符串入栈
stack_digit.push(digit);
stack_string.push(res);
digit=0;
res=new StringBuilder();
}else if(ch==']'){
//如果是"]"将数字和字符串出栈,此时临时字符串
//res=出栈字符串+出栈数字*res;
StringBuilder temp=stack_string.poll();
int count=stack_digit.poll();
for(int j=0;j<count;j++){
temp.append(res.toString());
}
res=temp;
}else if(Character.isDigit(ch)){
//如果是数字,放入临时数字中
digit=digit*10+ch-'0';
}else{
//如果是字符,直接将字符放在临时字符串中
res.append(ch);
}
}
return res.toString();
}
}