【C++ 算法进阶】算法提升八

复杂计算 (括号问题相关递归套路 重要)

题目

给定一个字符串str str表示一个公式 公式里面可能有整数 + - * / 符号以及左右括号 返回最终计算的结果

题目分析

本题的难点主要在于可能会有很多的括号 而我们直接模拟现实中的算法的话code会难写 要考虑的情况很多

那么我们首先写出加入没有括号应该怎么计算呢

我们这里只需要首先计算乘法和除法 再计算加法和减法

代码

int process(string& s1) {
	// s1 表示计算的公式
	stack<string> st;
	int cur = 0;

	for (int i = 0; i < s1.size(); i++) {
		if (s1[i] < '0' || s1[i] > '9')
		{
			if (!st.empty()) {
				string test = st.top();
				if (test == "*" || test == "/") {
					string op = st.top();
					st.pop();

					int left = stoi(st.top());
					st.pop();

					int right = cur;
					if (op == "*") {
						cur = left * right;
					}
					else
					{
						cur = left / right;
					}
				}

			}

			st.push(to_string(cur));
			string ops = string(1, s1[i]);
			st.push(ops);
			cur = 0;
		}
		else
		{
			cur = cur * 10 + (s1[i] - '0');
		}
	}

	string test = st.top();
	if (test == "*" || test == "/") {
		string op = st.top();
		st.pop();

		int left = stoi(st.top());
		st.pop();

		int right = cur;
		if (op == "*") {
			cur = left * right;
		}
		else
		{
			cur = left / right;
		}
	}
	st.push(to_string(cur));

	stack<string> st2;
	while (!st.empty())
	{
		st2.push(st.top());
		st.pop();
	}
	// 最后我们按照顺序计算栈里面的结果
	while (st2.size() != 1)
	{
		int left = stoi(st2.top());
		st2.pop();

		string op = st2.top();
		st2.pop();

		int right = stoi(st2.top());
		st2.pop();

		if (op == "+") {
			st2.push(to_string(left + right));
		}
		else
		{
			st2.push(to_string(left - right));
		}

	}

	return stoi(st2.top());
}

如果遇到括号怎么办呢

在这里插入图片描述

比如说我们现在计算到* 之后 遇到了一个 (

此时我们不进行继续的计算 而是使用递归 将这个括号里的内容传递给下个函数进行计算 我们只需要知道返回值即可

当然只知道返回值是不够的 因为我们还需要知道递归函数返回之后需要从哪一个位置开始计算

所以说递归函数的返回值要返回一个数组 数组里面存储着括号内计算的数值以及指针走到的位置

vector<int> process(string& s1 , int n ) {
	// s1代表字符串
	int i = n;
	int cur = 0;
	stack<string> st;

	while (i < s1.size() && s1[i] != ')')
	{
		if ((s1[i] < '0' || s1[i] > '9' ) && s1[i] != '(')
		{
			if (!st.empty()) {
				string test = st.top();
				if (test == "*" || test == "/") {
					string op = st.top();
					st.pop();

					int left = stoi(st.top());
					st.pop();

					int right = cur;
					if (op == "*") {
						cur = left * right;
					}
					else
					{
						cur = left / right;
					}
				}
			}

			st.push(to_string(cur));
			string ops = string(1, s1[i]);
			st.push(ops);
			cur = 0;
			i++;
		}
 		else if (s1[i] >= '0' && s1[i] <= '9')
		{
			cur = cur * 10 + (s1[i] - '0');
			i++;
		}
		else
		{
			vector<int> ans = process(s1 , i + 1);
			i = ans[1];
			cur = ans[0];
		}
	}

	// 走到这里说明碰到了边界了
	string test = st.top();
	if (test == "*" || test == "/") {
		string op = st.top();
		st.pop();

		int left = stoi(st.top());
		st.pop();

		int right = cur;
		if (op == "*") {
			cur = left * right;
		}
		else
		{
			cur = left / right;
		}
	}
	st.push(to_string(cur));

	stack<string> st2;
	while (!st.empty())
	{
		st2.push(st.top());
		st.pop();
	}
	// 最后我们按照顺序计算栈里面的结果
	while (st2.size() != 1)
	{
		int left = stoi(st2.top());
		st2.pop();

		string op = st2.top();
		st2.pop();

		int right = stoi(st2.top());
		st2.pop();

		if (op == "+") {
			st2.push(to_string(left + right));
		}
		else
		{
			st2.push(to_string(left - right));
		}
	}

	return { stoi(st2.top()), i + 1 };
}

我们只需要在遇到左括号的时候将计算的任务丢给递归函数 也就是调用下面这段代码

		else
		{
			vector<int> ans = process(s1 , i + 1);
			i = ans[1];
			cur = ans[0];
		}

即可

装最多水的容器 (贪心)

题目

本题为LC原题 题目如下

在这里插入图片描述

题目分析

装水的容积由两个部分决定

  1. 两块板子之间的宽度
  2. 两块板子中较小的那块板子的高度

所以说 只要我们找出每个宽度的最大值 最后对比一下 我们就能得出最终答案

所以说我们一开始自然是用最左和最右边的板子装水

之后宽度-- 那么我们要想得到最大值是不是要在高度上花心思

我们肯定要舍弃掉较为短的一块板子

之后用代码实现上述内容即可

代码

class Solution {
public:
    int maxArea(vector<int>& height) {
        int left = 0;
        int right = height.size() - 1;
        int ans = 0;

        while (left < right) {
            int h = min(height[left] , height[right]);
            int w = right - left;
            ans = max(w * h , ans);

            if (height[left] < height[right]) {
                left++;
            }else {
                right--;
            }
        }

        return ans;
    }
};

蛇走格子问题 (动态规划)

题目

假设现在有一个二维数组 每个位置存放着一个整数 (可以为负)

现在有一条蛇要从这个数组的最左边开始找出一条整数相加为最大值的路径

蛇只能往右上 右 右下走

如果叠加到负数则蛇立刻死亡(之前成绩归为-1)

蛇有一种能力 只能发动一次 可以让格子的值变成相反数

题目分析

这是一道经典的动态规划问题 我们可以设计一个如下的函数

// 数组arr上返回i j位置的info信息  
// info信息 使用了能力和没有使用能力返回的最大值
info process(vector<vector<int>>& arr, int i, int j) {
}

之后只要跟着递归三部走

  • 找终止条件
  • 找可能性
  • 返回最终结果

即可

终止条件为 当J == 0的时候 我们只有此时用不用能力这两种选择

可能性就有很多了 总体可以分为两类

  • 没用能力
  • 用了能力
    当然 用了能力还要区分 是不是这次用的

之后如果前面的结果有-1 我们则要将其排除出可能性(即答案设置为-1)

代码

// 数组arr上返回i j位置的info信息  
// info信息 使用了能力和没有使用能力返回的最大值
info* process(vector<vector<int>>& arr, int i, int j) {
	if (j == 0)
	{
		// 不使用能力 -1表示可能达到
		int no = arr[i][j] >= 0 ? arr[i][j] : -1;
		int yes = -arr[i][j] >= 0 ? -arr[i][j] : -1;
		return new info(no, yes);
	}
	
	// 真正的可能性
	// 首先肯定有左边
	int preno = -1;
	int preyes = -1;

	auto info1 = process(arr, i, j);
	preno = max(info1->_no, preno);
	preyes = max(info1->_yes, preyes);

	if (i > 0)
	{
		auto info1 = process(arr, i - 1, j - 1);
		preno = max(info1->_no, preno);
		preyes = max(info1->_yes, preyes);
	}

	if (i < arr.size() - 1)
	{
		auto info1 = process(arr, i + 1, j - 1);
		preno = max(info1->_no, preno);
		preyes = max(info1->_yes, preyes);
	}

	// 列可能性
	int p1 = preno + arr[i][j];
	if (p1 < 0)
	{
		p1 = -1;
	}

	if (preno = -1)
	{
		p1 = -1;
	}

	int p2 = preyes + arr[i][j];
	int p3 = preno - arr[i][j];
	p2 = max(p2, p3);
	if (p2 < 0)
	{
		p2 = -1;
	}

	if (preyes = -1)
	{
		p2 = -1;
	}
	if (preno = -1)
	{
		p3 = -1;
	}

	
	return new info(p1, p2);
}

int _process(vector<vector<int>>& arr) {
	int ans = 0;
	for (int i = 0; i < arr.size(); i++) {
		for (int j = 0; j < arr[0].size(); j++)
		{
			auto res = process(arr, i, j);
			ans = max(ans, max(res->_no, res->_yes));
		}
	}

	return ans;
}

路径问题 (动态规划)

题目

给定你一个二维数组 二维数组中存放着a~z的二十六个字符 再给你一个字符串str

现在请问 从这个二维数组中的任意一个位置开始找 是否能找到一条路径能组成字符串str

  1. 如果路径可以重复是否可以组成
  2. 如果路径不能重复是否可以组成

题目分析

凡是动态规划的题目我们首先来想思路 因为题目中是一个二维数组 所以我们肯定要使用两个变量来标识唯一一个位置

此外对于字符串str 我们也需要一个变量来确定位置

// 这个函数的意义是从i j位置开始 arr中的字符能不能组成包括str[K]位置及其往后所有位置
bool process(vector<vector<char>>& arr, int i, int j, int k) {
}

我们验证当前字符是否符合之后 只需要调用递归函数查看下一个函数是否符合即可

// 这个函数的意义是从i j位置开始 arr中的字符能不能组成包括str[K]位置及其往后所有位置
bool process(vector<vector<char>>& arr, string& str,int i, int j, int k) {
	if (k == str.size())
	{
		return true;
	}

	if (i < 0 || i > arr.size() - 1 || j < 0 || j > arr[0].size() - 1 || arr[i][j] != str[k])
	{
		return false;
	}

	bool ans = false;
	// 可能性 走到这里说明前面都符合
	if (process(arr, str, i + 1, j + 1, k + 1) || process(arr, str, i + 1, j - 1, k + 1) || process(arr, str, i - 1, j + 1, k + 1)
		|| process(arr, str, i - 1, j - 1, k + 1))
	{
		ans = true;
	}

	return ans;
}

如果不允许路径重复呢?

这个问题的难点实际在于我们如何标记之前走过的路径

这里推荐使用回溯法

我们每次走过一个路径的之后将当前格子标0

之后验证完毕之后再将格子改回去就行

bool process(vector<vector<char>>& arr, string& str,int i, int j, int k) {
	if (k == str.size())
	{
		return true;
	}

	if (i < 0 || i > arr.size() - 1 || j < 0 || j > arr[0].size() - 1 || arr[i][j] != str[k])
	{
		return false;
	}

	arr[i][j] = 0;
	bool ans = false;
	// 可能性 走到这里说明前面都符合
	if (process(arr, str, i + 1, j + 1, k + 1) || process(arr, str, i + 1, j - 1, k + 1) || process(arr, str, i - 1, j + 1, k + 1)
		|| process(arr, str, i - 1, j - 1, k + 1))
	{
		ans = true;
	}

	arr[i][j] = str[k];
	return ans;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/905402.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

​IOT NTN 与 NR NTN​

NTN&#xff08;Non-Terrestrial Network)&#xff09;&#xff0c;即非地面网络通信&#xff0c;通过不同轨道高度的卫星对地面上的终端提供网络连接的服务。利用卫星通信网络与地面蜂窝网络的融合&#xff0c;可以在不受地形地貌的限制和影响下&#xff0c;连通空、天、地、海…

44-RK3588s调试 camera-engine-rkaiq(rkaiq_3A_server)

在RK3588s平台上调试imx415 camera sensor 过程中&#xff0c;已经识别到了camera sensor ID&#xff0c;并且可以拿到raw图和isp处理后的图像&#xff0c;但是isp处理后的图像偏绿&#xff0c;来看查看后台服务发现rkaiq_3A_server没有运行&#xff0c;然后单独运行rkaiq_3A_s…

【深度学习中的注意力机制10】11种主流注意力机制112个创新研究paper+代码——交叉注意力(Cross-Attention)

【深度学习中的注意力机制10】11种主流注意力机制112个创新研究paper代码——交叉注意力&#xff08;Cross-Attention&#xff09; 【深度学习中的注意力机制10】11种主流注意力机制112个创新研究paper代码——交叉注意力&#xff08;Cross-Attention&#xff09; 文章目录 【…

springboot响应文件流文件给浏览器+前端下载

springboot响应文件流文件给浏览器前端下载 1.controller: Api(tags {"【样本提取系统】-api"}) RestController("YbtqYstbtqController") RequiredArgsConstructor RequestMapping("/ybtq-ystbtq") Slf4j public class YbtqYstbtqController …

DAY67WEB 攻防-Java 安全JNDIRMILDAP五大不安全组件RCE 执行不出网

知识点&#xff1a; 1、Java安全-RCE执行-5大类函数调用 2、Java安全-JNDI注入-RMI&LDAP&高版本 3、Java安全-不安全组件-Shiro&FastJson&JackJson&XStream&Log4j Java安全-RCE执行-5大类函数调用 Java中代码执行的类&#xff1a; Groovy Runti…

vue下载安装

目录 vue工具前置要求&#xff1a;安装node.js并配置好国内镜像源下载安装 vue 工具 系统&#xff1a;Windows 11 前置要求&#xff1a;安装node.js并配置好国内镜像源 参考&#xff1a;本人写的《node.js下载、安装、设置国内镜像源&#xff08;永久&#xff09;&#xff…

书生实战营第四期-第四关 玩转HF/魔搭/魔乐社区

一、任务1&#xff1a;模型下载 使用魔搭社区平台下载文档中提到的模型 1.创建开发机 2.环境配置 # 激活环境 conda activate /root/share/pre_envs/pytorch2.1.2cu12.1# 安装 modelscope pip install modelscope -t /root/env/maas pip install numpy1.26.0 -t /root/env/m…

【Blender】 学习笔记(一)

文章目录 参考概念原点 Origin游标 轴心点坐标操作默认快捷键两个比较好用的功能渲染器元素不可选&#xff08;防止误选&#xff09;关联材质 参考 参考b站视频&#xff1a;【Kurt】Blender零基础入门教程 | Blender中文区新手必刷教程(已完结) 概念 模型、灯光、摄像机 原点…

Java中的反射(Reflection)

先上两张图来系统的看一下反射的作用和具体的实现方法 接下来详细说一下反射的步骤以及之中使用的方法&#xff1a; 获取Class对象&#xff1a; 要使用反射&#xff0c;首先需要获得一个Class对象&#xff0c;该对象是反射的入口点。可以通过以下几种方式获取Class对象&#x…

号码认证是什么意思?有什么用?

随着通信环境越来越复杂&#xff0c;各种骚扰、推销电话层出不穷。许多企业为了取信于客户&#xff0c;提高电话的接听率&#xff0c;纷纷选择了申请号码认证&#xff0c;试图通过这种方法来与客户建立更加高效的沟通。 不可否认&#xff0c;这种方法是极其有效的。号码认证可…

Android 圆形进度条CircleProgressView 基础版

一个最基础的自定义View 圆形进度条&#xff0c;可设置背景色、进度条颜色&#xff08;渐变色&#xff09;下载进度控制&#xff1b;可二次定制度高&#xff1b; 核心代码&#xff1a; Overrideprotected void onDraw(NonNull Canvas canvas) {super.onDraw(canvas);int mW g…

Java基础0-Java概览

Java概览 一、Java的主要特性 Java 语言是简单的&#xff1a; Java 丢弃了 C 中很少使用的、很难理解的、令人迷惑的那些特性&#xff0c;如操作符重载、多继承、自动的强制类型转换。特别地&#xff0c;Java 语言不使用指针&#xff0c;而是引用。并提供了自动分配和回收内存…

信号(四)【信号处理与捕捉】

目录 1. 信号的处理1.1 内核态 && 用户态1.2 进程地址空间第三弹1.1 内核态 && 用户态 (续) 2. 信号捕捉 1. 信号的处理 我们一直在说&#xff0c;进程收到信号了&#xff0c;可能会因为各种原因无法即使处理信号&#xff0c;而后选择一个合适的时机去处理。所…

Kafka 与传统 MQ 消息系统之间有三个关键区别?

大家好&#xff0c;我是锋哥。今天分享关于【Kafka 与传统 MQ 消息系统之间有三个关键区别&#xff1f;】面试题&#xff1f;希望对大家有帮助&#xff1b; Kafka 与传统 MQ 消息系统之间有三个关键区别&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 …

基于局部近似的模型解释方法

在机器学习领域中&#xff0c;模型解释性是一个越来越重要的议题&#xff0c;尤其是在复杂的深度学习模型和非线性模型广泛应用的今天。解释性不仅帮助我们理解模型的决策逻辑&#xff0c;还能提高模型在敏感领域&#xff08;如医疗诊断、金融分析&#xff09;中的可信度。基于…

img 标签的 object-fit 属性

设置图片固定尺寸后&#xff0c;可以通过 object-fit 属性调整图片展示的形式 object-fit: contain; 图片的长宽比不变&#xff0c;相应调整大小。 object-fit: cover; 当图片的长宽比与容器的长宽比不一致时&#xff0c;会被裁切。 object-fit: fill; 图片不再锁定长宽…

推荐一款功能强大的文字处理工具:Atlantis Word Processor

Atlantis word proCEssor是一款功能强大的文字处理工具。该软件可以让用户放心的去设计文档&#xff0c;并且软件的界面能够按用户的意愿去自定义&#xff0c;比如工具栏、字体选择、排版、打印栏等等&#xff0c;当然还有更多的功能&#xff0c;比如你还可以吧软件界面中的任何…

【算法】【优选算法】双指针(上)

目录 一、双指针简介1.1 对撞指针&#xff08;左右指针&#xff09;1.2 快慢指针 二、283.移动零三、1089.复写零3.1 双指针解题3.2 暴力解法 四、202.快乐数4.1 快慢指针4.2 暴力解法 五、11.盛最多⽔的容器5.1 左右指针5.2 暴力解法 一、双指针简介 常⻅的双指针有两种形式&…

Pandas DataFrame学习补充

1. 从字典创建&#xff1a;字典的键成为列名&#xff0c;值成为列数据。 import pandas as pd# 通过字典创建 DataFrame df pd.DataFrame({Column1: [1, 2, 3], Column2: [4, 5, 6]}) 2. 从列表的列表创建&#xff1a;外层列表代表行&#xff0c;内层列表代表列。 df pd.Da…

二、Go快速入门之数据类型

&#x1f4c5; 2024年4月27日 &#x1f4e6; 使用版本为1.21.5 Go的数据类型 &#x1f4d6;官方文档&#xff1a;https://go.dev/ref/spec#Types 1️⃣ 布尔类型 ⭐️ 布尔类型只有真和假,true和false ⭐️ 在Go中整数0不会代表假&#xff0c;非零整数也不能代替真&#…