常见算法题分类总结之递归与栈(Stack):解决表达式求值

我们先来看什么是递归

什么是递归?

从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢
!故事是什么呢?
“从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!
故事是什么呢?
‘从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢! 故事是什么呢?……’”

递归的解题思路
递归程序的基本步骤:
(1) 初始化算法。递归程序通常需要一个开始时使用的种子值(seed value)。要完成此任务, 可以向函数传递参数,或者提供一个入口函数, 这个函数是非递归的,但可以为递归计算设 置种子值。
(2) 检查要处理的当前值是否已经与基线条件相匹配。如果匹配,则进行处理并返回值。
(3) 使用更小的或更简单的子问题(或多个子问题)来重新定义答案。
(4) 对子问题运行算法。
(5) 将结果合并入答案的表达式。
(6) 返回结果。

需要注意的点:
• 递归出口(终止递归的条件)
• 递归表达式(规律)

记忆化
我们将进一步研究递归可能出现的重复计算问题。 然后我们将提出一种常用的技术, 称为记忆化(memoization),可以用来避免重复计算问题
记忆化是一种优化技术,主要用于加快计算机程序的速度,方法是存储昂贵的函数调 用的结果,并在相同的输入再次出现时返回缓存的结果
简单点:就是用存储来存中间值,避免重复计算

总结
递归是一门伟大的艺术,使得程序的正确性更容易确认,而不需要牺牲性能,但这需 要程序员以一种新的眼光来研究程序设计。对新程序员 来说,命令式程序设计通常 是一个更为自然和直观的起点,这就是为什么大部分程序设计说明都集中关注命令式 语言和方法的原因。 不过,随着程序越来越复杂,递归程序设计能够让程序员以可 维护且逻辑一致的方式更好地组织代码

什么是“栈”?
关于“栈”,有一个非常贴切的例子,就是往枪里面装子弹。装子弹的时候都是从前往 后一个一个进;打枪发射子弹的时候,是后装的子弹先出,先进的子弹后出,子弹不能 从中间任意出。后进者先出,先进者后出,这就是典型的“栈”结构。
栈相对数组和链表貌似只有限制没有任何优势。其实从功能上来说,数组或链表确实可 以替代栈,但是存在即合理,每⼀种数据结构都是在特定的使⽤场景下的抽象,⽽且, 数组或链表虽然操作上的确灵活⾃由,但使⽤时就⽐较不可控,⾃然也就更容易出错。 当某个数据集合只涉及在⼀端插⼊和删除数据,并且满⾜后进先出、先进后出的特性, 这时我们就应该⾸选“栈”这种数据结构。
栈的插入删除操作 栈的操作只允许在一端插入和删除数据,仅在表尾进行插入和删除操作,这一端被称为 栈顶,另一端称为栈低,是一种“操作受限”的线性表。
push入栈:向一个栈插入新元素称为进栈(入栈或压栈)新元素放在栈顶元素上面,使 之成为新的栈顶元素; pop出栈:从一个栈删除元素称为出栈或退栈,是将栈顶元素删除掉。
⾸先取出近添加的数据的⽅法称为“后进先出”(Last In First Out)简称:LIFO 

栈的应⽤场景

 表达式的转换:中缀转后缀与求值
 递归⽅式就是函数⾃身调⽤⾃身,当递归每次调⽤⾃身时,可以看作是⼊栈的过程,当递 归条件满⾜后,结束时递归再⼀级⼀级的返回,返回过程可以看作是出栈的过程。递归和 栈的实现过程可以看出都是符合“先进后出,后⼊先出”的原则,所以递归⽅式其实可以转 化为栈的⽅式来实现。
 对于⼆叉树的遍历,先序、中序、后序遍历都可以⽤到递归⽅法实现,既然递归可以转化 为栈,那么如何把对⼆叉树的遍历也改为⽤栈的思想来实现
 

 栈实现综合计算器
请输⼊⼀个表达式,计算式:7*2*2-5+1-5+3-3 请问计算机底层如何运算得到结果?注意不是简单的把算式列出运算,对于计算机来说他是⼀ 个字符串。
思路:
1、通过index值遍历表达式
2、如果发现是⼀个数字⼊数栈
3、如果扫描到的是符号分以下情况:
         如果符号栈为空直接⼊栈
         如果符号栈有操作符进⾏⽐较
         如果当前的操作符的优先级⼩于或者等于栈中的操作符。需要从数栈中pop出2个 数,再从符号栈中pop出⼀个符号进⾏运算,将得到的结果⼊数栈,然后将当前 操作符⼊符号栈
         如果当前的操作符的优先级⼤于栈中的操作符直接⼊符号栈。
4、当表达式扫描结束就顺序的从数栈和符号栈中pop相应的数和符号并运⾏
5、后在数栈中只有⼀个数字就是表达式的结果

/**
 * 有效括号
 * @author: William
 * @time:2022-03-10
 */

public class Num20 {
	//map记录括号关系,栈放左括号
	public boolean isValid(String s) {
        Map<Character, Character> map = new HashMap<>();
        map.put(')', '(');
		map.put(']', '[');
		map.put('}', '{');
        Stack<Character> stack = new Stack<>();
        for(int i = 0; i < s.length(); i++){
            switch(s.charAt(i)){
                case '(':
				case '[':
				case '{':
                    stack.push(s.charAt(i));
                    break;
                case ')':
				case ']':
				case '}':
                //栈空了或者右括号匹配不上左括号
                    if(stack.isEmpty() || map.get(s.charAt(i)) != stack.peek()) return false;
                //配对成功,弹出左括号
                stack.pop();
                break;
            }
        }
        //判断左括号有没有多
        return stack.isEmpty();
    }
	
	 public boolean isValid1(String s) {
		 int n = s.length();
		 if(n % 2 == 1) return false;
		 
		 Map<Character, Character> pairs = new HashMap<Character, Character>(){
  
  {
			 put(')', '(');
	         put(']', '[');
	         put('}', '{');
		 }};
		 Deque<Character> stack = new LinkedList<Character>();
		 for(int i = 0; i < n; i++) {
			 char ch = s.charAt(i);
			 if(pairs.containsKey(ch)) {
				 if(stack.isEmpty() || stack.peek() != pairs.get(ch)) {
					 return false;
				 }
				 stack.pop();
			 }else {
				 stack.push(ch);
			 }
		 }
		 return stack.isEmpty();
	 }
	
	//用哈希提前返回
	private static final Map<Character,Character> map = new HashMap<
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值