【性能优化】 【回溯】 【字符串】1307. 口算难题

作者推荐

视频算法专题

本文涉及知识点

数学 回溯 字符串 性能优化

LeetCode1307. 口算难题

给你一个方程,左边用 words 表示,右边用 result 表示。
你需要根据以下规则检查方程是否可解:
每个字符都会被解码成一位数字(0 - 9)。
每对不同的字符必须映射到不同的数字。
每个 words[i] 和 result 都会被解码成一个没有前导零的数字。
左侧数字之和(words)等于右侧数字(result)。
如果方程可解,返回 True,否则返回 False。
示例 1:
输入:words = [“SEND”,“MORE”], result = “MONEY”
输出:true
解释:映射 ‘S’-> 9, ‘E’->5, ‘N’->6, ‘D’->7, ‘M’->1, ‘O’->0, ‘R’->8, ‘Y’->‘2’
所以 “SEND” + “MORE” = “MONEY” , 9567 + 1085 = 10652
示例 2:

输入:words = [“SIX”,“SEVEN”,“SEVEN”], result = “TWENTY”
输出:true
解释:映射 ‘S’-> 6, ‘I’->5, ‘X’->0, ‘E’->8, ‘V’->7, ‘N’->2, ‘T’->1, ‘W’->‘3’, ‘Y’->4
所以 “SIX” + “SEVEN” + “SEVEN” = “TWENTY” , 650 + 68782 + 68782 = 138214
示例 3:

输入:words = [“THIS”,“IS”,“TOO”], result = “FUNNY”
输出:true
示例 4:

输入:words = [“LEET”,“CODE”], result = “POINT”
输出:false

提示:

2 <= words.length <= 5
1 <= words[i].length, results.length <= 7
words[i], result 只含有大写英文字母
表达式中使用的不同字符数最大为 10

回溯

简单的例子
AB + AC = BCD
10A+B+10A+C = 100B+10C+D
20A-99B -9C-D = 0
系数20,-99,-9,-1 放到向量v中,并排序。如果直接回溯,时间复杂度1010超时。
将v排序,从后到前处理。处理v[i],先估算v[0,i)的最小值iMin和最大值iMax,如果已有值x+iMin > 0或 x+iMax < 0,则剪枝忽略。
求最小值:
如果存在负数,最小的负数(绝对值最大)对应最大的未选择值。如果存在正数,最大的正数取最小的未选择数。
求最大值:
如果存在负数,最小的负数(绝对值最大)对应最小的未选择值。如果存在正数,最大的正数取最大的未选择数。

代码

核心代码(超时)

class Solution {
public:
	bool isSolvable(vector<string>& words, string result) {
		unordered_map<char, int> mCharCnt;	
		unordered_map<char, bool> mCharNot0;//开头不能为0
		auto Add = [&](int iMul, const string& s)
		{
			for (int i = s.length() - 1; i >= 0; i--, iMul*=10)
			{
				mCharCnt[s[i]] += iMul;
			}
			if (s.length() > 1)
			{
				mCharNot0[s[0]] = true;
			}
		};
		for (const auto& s : words)
		{
			Add(1, s);
		}
		Add(-1, result);
		vector<pair<int,int>> v;
		for (const auto& [tmp, cnt] : mCharCnt)
		{
			v.emplace_back(cnt,mCharNot0[tmp]);
		}
		sort(v.begin(), v.end());
		set<int> setSel;
		for (int i = 0; i < 10; i++)
		{
			setSel.emplace(i);
		}
		return DFS(v, setSel, 0, 0);
	}
	template<class Pr>
	int MinMax(const pair<int, int>*p, int n, set<int,Pr> setSel)
	{
		int result = 0;
		for (int i = 0; i != n;)
		{
			if (p[i].first < 0)
			{
				result += *setSel.begin()*p[i++].first;
				setSel.erase(setSel.begin());
			}
			else
			{
				result += *setSel.rbegin()*p[--n].first;
				setSel.erase(std::prev(setSel.end()));
			}
		}
		return result;
	}
	bool DFS(const vector<pair<int,int>> & v, set<int>& setSel, int leve, int result)
	{
		if (v.size() == leve)
		{
			return 0 == result;
		}
		const int iMin = MinMax(v.data()+leve, v.size()-leve, set<int, std::greater<int>>(setSel.begin(), setSel.end()));
		const int iMax = MinMax(v.data() + leve, v.size() - leve, setSel);
		if ((iMin + result > 0) || (iMax + result < 0))
		{
			return false;
		}
		for (int i = 9; i >= v[leve].second; i--)
		{
			if (!setSel.count(i))
			{
				continue;
			}
			setSel.erase(i);			
			if (DFS(v, setSel, leve + 1, result + v[leve].first * i))
			{
				return true;
			}
			setSel.emplace(i);
		}
		return false;
	}	
};

测试用例

template<class T,class T2>
void Assert(const T& t1, const T2& t2)
{
	assert(t1 == t2);
}

template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{
	if (v1.size() != v2.size())
	{
		assert(false);
		return;
	}
	for (int i = 0; i < v1.size(); i++)
	{
		Assert(v1[i], v2[i]);
	}

}

int main()
{
	vector<string> words;
	string result;
	{
		Solution sln;
		words = { "A","B" }, result = "A";
		auto res = sln.isSolvable(words, result);
		Assert(true, res);
	}
	{
		Solution sln;
		words = { "CBA","CBA","CBA","CBA","CBA" }, result = "EDD";
		auto res = sln.isSolvable(words, result);
		Assert(false, res);
	}
	{
		Solution sln;
		words = { "SEND", "MORE" }, result = "MONEY";
		auto res = sln.isSolvable(words, result);
		Assert(true, res);
	}
	{
		Solution sln;
		words = { "SIX", "SEVEN", "SEVEN" }, result = "TWENTY";
		auto res = sln.isSolvable(words, result);
		Assert(true, res);
	}
	{
		Solution sln;
		words = { "THIS", "IS", "TOO" }, result = "FUNNY";
		auto res = sln.isSolvable(words, result);
		Assert(true, res);
	}
	{
		Solution sln;
		words = { "LEET", "CODE" }, result = "POINT";
		auto res = sln.isSolvable(words, result);
		Assert(false, res);
	}
}

估算最小值最大值

pair<int,int> MinMaxSingle(const pair<int, int>* p, int n)
{
	int less0 = 0, more0 = 0;
	for (int i = 0; i < n ; i++ )
	{
		if (p[i].first < 0)
		{
			less0 += p[i].first;
		}
		else
		{
			more0 += p[i].first;
		}
	}
	return { less0 * 9,more0 * 9 };
}

可以提升一倍,还是过不了。
一,for循环也可以省略。
二,向量变原生数组。
这两个方法效果很小。

class Solution {
public:
	bool isSolvable(vector<string>& words, string result) {
		unordered_map<char, int> mCharCnt;	
		unordered_map<char, bool> mCharNot0;//开头不能为0
		auto Add = [&](int iMul, const string& s)
		{
			for (int i = s.length() - 1; i >= 0; i--, iMul*=10)
			{
				mCharCnt[s[i]] += iMul;
			}
			if (s.length() > 1)
			{
				mCharNot0[s[0]] = true;
			}
		};
		for (const auto& s : words)
		{
			Add(1, s);
		}
		Add(-1, result);
		pair<int, int> v[10];
		int less0 = 0, more0 = 0;
		for (const auto& [tmp, cnt] : mCharCnt)
		{
			v[m_c++] = { cnt,mCharNot0[tmp] };			
			if (cnt < 0)
			{
				less0 += cnt;
			}
			else
			{
				more0 += cnt;
			}
		}
		sort(v, v+m_c);
		set<int> setSel;
		for (int i = 0; i < 10; i++)
		{
			setSel.emplace(i);
		}
		return DFS(v, setSel, 0, 0,more0,less0);
	}
	bool DFS(const pair<int, int>* p, set<int>& setSel, int leve, int result,int more0,int less0)
	{
		if (m_c == leve)
		{
			return 0 == result;
		}
		if ((less0*9 + result > 0) || (more0*9 + result < 0))
		{
			return false;
		}
		for (int i = 9; i >= p[leve].second; i--)
		{
			if (!setSel.count(i))
			{
				continue;
			}
			setSel.erase(i);		
			const int curLess0 = min(0, p[leve].first);
			const int curMore0 = max(0, p[leve].first);
			if (DFS(p, setSel, leve + 1, result + p[leve].first * i,more0+curMore0,less0+curLess0))
			{
				return true;
			}
			setSel.emplace(i);
		}
		return false;
	}	
	int m_c = 0;
};

先处理绝对值大的

速度提升大约1000倍。

class Solution {
public:
	bool isSolvable(vector<string>& words, string result) {
		unordered_map<char, int> mCharCnt;	
		unordered_map<char, bool> mCharNot0;//开头不能为0
		auto Add = [&](int iMul, const string& s)
		{
			for (int i = s.length() - 1; i >= 0; i--, iMul*=10)
			{
				mCharCnt[s[i]] += iMul;
			}
			if (s.length() > 1)
			{
				mCharNot0[s[0]] = true;
			}
		};
		for (const auto& s : words)
		{
			Add(1, s);
		}
		Add(-1, result);
		pair<int, int> v[10];
		int less0 = 0, more0 = 0;
		for (const auto& [tmp, cnt] : mCharCnt)
		{
			v[m_c++] = { cnt,mCharNot0[tmp] };			
			if (cnt < 0)
			{
				less0 += cnt;
			}
			else
			{
				more0 += cnt;
			}
		}
		sort(v, v + m_c, [&](const auto& pr1, const auto& pr2) {return abs(pr1.first) > abs(pr2.first); });
		set<int> setSel;
		for (int i = 0; i < 10; i++)
		{
			setSel.emplace(i);
		}
		return DFS(v, setSel, 0, 0,more0,less0);
	}
	bool DFS(const pair<int, int>* p, set<int>& setSel, int leve, int result,int more0,int less0)
	{
		if (m_c == leve)
		{
			return 0 == result;
		}
		if ((less0*9 + result > 0) || (more0*9 + result < 0))
		{
			return false;
		}
		for (int i = 9; i >= p[leve].second; i--)
		{
			if (!setSel.count(i))
			{
				continue;
			}
			setSel.erase(i);		
			const int curLess0 = min(0, p[leve].first);
			const int curMore0 = max(0, p[leve].first);
			if (DFS(p, setSel, leve + 1, result + p[leve].first * i,more0-curMore0,less0-curLess0))
			{
				return true;
			}
			setSel.emplace(i);
		}
		return false;
	}	
	int m_c = 0;
};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关

下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

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

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

相关文章

R: 网状Meta分析进行模型构建及图形绘制

网状meta分析的制作步骤主要包括&#xff1a; 1. 绘制网状证据图 2. 普通Meta分析&#xff08;两两之间的直接比较&#xff09; 3. 网状Meta分析&#xff08;整合直接比较和间接比较的结果&#xff0c;绘制相关图形&#xff09; 4. 绘制累积概率排序图 5. 三个假设的检验…

【Linux】网络基础1

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;折纸花满衣 &#x1f3e0;个人专栏&#xff1a;题目解析 目录 &#x1f449;&#x1f3fb;一些常见网络设备&#x1f449;&#x1f3fb;网络协议(栈)&#x1f449;&#x1f3fb;协议分层OSI参考模型每个层…

CCF-CSP真题202206-2《寻宝!大冒险!》

题目背景 暑假要到了。可惜由于种种原因&#xff0c;小 P 原本的出游计划取消。失望的小 P 只能留在西西艾弗岛上度过一个略显单调的假期……直到…… 某天&#xff0c;小 P 获得了一张神秘的藏宝图。 问题描述 西西艾弗岛上种有 n 棵树&#xff0c;这些树的具体位置记录在…

【沐风老师】3DMAX顶点投影插件VertexProjection使用方法详解

3DMAX顶点投影插件VertexProjection使用教程 3DMAX顶点投影插件VertexProjection&#xff0c;将可编辑多边形顶点向下投影到网格对象表面。可以对可编辑多边形对象上的所有顶点或部分顶点进行投影。主要用于地形建模、道路交通等领域。 【适用版本】 3dMax 2010 - 2024&#x…

【前端】layui学习笔记

参考视频&#xff1a;LayUI 1.介绍 官网&#xff1a;http://layui.apixx.net/index.html 国人16年开发的框架,拿来即用,门槛低 … 2. LayUi的安装及使用 Layui 是一套开源的 Web UI 组件库&#xff0c;采用自身轻量级模块化规范&#xff0c;遵循原生态的 HTML/CSS/JavaScript…

解决VMWare Esxi 6.5.0 导出虚拟机时发生网络错误

解决办法&#xff1a;使用vmware ovftool工具导出。 1 先安装该工具到windows下面&#xff0c;有32位的和64位的 2 用管理员进入命令方式&#xff1a; 进入&#xff1a;c:\windows 进入工具命令当前文件夹&#xff08;具体看用户的安装路径&#xff09;&#xff1a; cd \p…

Docket常见的软件部署1

1 安装MySQL # 查看MySQL镜像 docker search mysql # 拉起镜像 docker pull mysql:5.7 # 创建MySQL数据映射卷&#xff0c;防止数据不丢失 mkdir -p /hmoe/tem/docker/mysql/data/ # 启动镜像 docker run -d --name mysql -e MYSQL_ROOT_PASSWORD123456 -p 3306:3306 -v /home…

(原型与原型链)前端八股文修炼Day5

一 原型链的理解 原型链定义&#xff1a; 原型链是 JavaScript 中实现对象继承的关键机制之一&#xff0c;它是一种对象之间的关系&#xff0c;通过这种关系&#xff0c;一个对象可以继承另一个对象的属性和方法。 原型链的组成&#xff1a; 每个对象都有一个指向另一个对象的…

抖音短视频矩阵系统源代码开发部署/SaaS贴牌/源码开源

抖音短视频矩阵系统的源代码开发部署可以分为以下几个步骤&#xff1a; 确定需求&#xff1a;首先&#xff0c;你需要确定你想要开发的具体功能和特性&#xff0c;比如用户注册、上传短视频、评论等。 开发源代码&#xff1a;根据需求&#xff0c;你可以选择使用合适的编程语言…

【安全用电管理系统的应用如何保证用电安全】Acrel-6000安科瑞智慧安全用电解决方案

政策背景 国家部委 ※2017年5月3日国务院安委会召开电气火灾综合治理工作视频会议&#xff0c;决定在全国范围内组织开展为期3年的电气火灾综合治理工作。 公安部领导 ※公安部副部长李伟强调&#xff1a;向科技要战斗力&#xff0c;加快推进“智慧消防”建设不断提升火灾防控…

通过组策略,统一发布桌面壁纸,并禁止用户更改

在Windows域环境中&#xff0c;可以通过组策略&#xff08;Group Policy&#xff09;来实现统一发布桌面壁纸并且禁止用户更改。以下是操作步骤&#xff1a; 打开“组策略管理”&#xff08;Group Policy Management Console, GPMC&#xff09;。 在GPMC中&#xff0c;选择你想…

操作系统:经典进程同步问题的高级探讨

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

存储卡数据如何恢复?6 个免费的 SD 卡恢复软件

SD 卡包含数字世界中的照片、电影、文档等。擦除、格式化或SD卡损坏都可能导致数据丢失&#xff0c;这一点值得警惕。这就是免费 SD 卡恢复软件有用的原因。使用该软件的三个主要原因&#xff1a; 经济高效&#xff1a;免费的 SD 卡恢复软件可帮助恢复丢失的数据&#xff0c;而…

2024年springboot+vue毕业设计选题推荐

2024年&#xff0c;随着技术的发展和市场需求的变化&#xff0c;基于Spring Boot和Vue的毕业设计选题可以更加注重新兴技术的融合和解决实际问题。以下是一些建议的选题方向&#xff1a; 1. 基于Spring Boot和Vue的智能健康管理系统 - 设计并实现一个集成了运动数据、睡眠监…

本地qwen 大模型,基于FastAPI构建API接口使用

文章目录 简介实战API 构建访问curlrequest库 结果参考资料 简介 实战 使用modelscope 下载千问7B模型&#xff0c;利用FastAPI部署成在线的API接口&#xff1b; 使用history历史对话多轮问答数据&#xff0c;实现多轮对话&#xff1b; API 构建 import uvicorn from fasta…

【C语言】Infiniband驱动pci_pcie_cap

一、注释 //include\linux\compat-2.6.h #define LINUX_BACKPORT(__sym) backport_ ##__sym//include\linux\compat-2.6.33.h #define pci_pcie_cap LINUX_BACKPORT(pci_pcie_cap)/*** pci_pcie_cap - 获取保存的PCIe能力偏移* dev: PCI 设备** PCIe能力偏移在PCI设备初始化时…

vue3+Vite+TS项目,配置ESlint和Prettier

创建vue3项目 实操过的有两种方式 1.vue脚手架2.vite&#xff08;推荐&#xff0c;也是尤大大团队研发&#xff09; 具体怎么新建一个vue3项目就不多讲了&#xff0c;可以按照官方文档来 创建后的文件目录长这样 多提一句&#xff0c;vite也会随着时间不断迭代&#xff0c;后…

方格分割(蓝桥杯)

文章目录 方格分割题目描述答案&#xff1a;509思路dfs 方格分割 题目描述 本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。 6x6的方格&#xff0c;沿着格子的边线剪开成两部分。 要求这两部分的形状完全相同。 如下就是三…

蓝桥杯基础练习汇总详细解析(三)——字母图形、01字符串、闰年判断(详细解题思路、代码实现、Python)

试题 基础练习 字母图形 提交此题 评测记录 资源限制 内存限制&#xff1a;256.0MB C/C时间限制&#xff1a;1.0s Java时间限制&#xff1a;3.0s Python时间限制&#xff1a;5.0s 问题描述 利用字母可以组成一些美丽的图形&#xff0c;下面给出了一个例子&#…

汇编语言学习记录 01

目录 VScode配置调试环境 Debug的主要命令 简单写个Hello World VScode配置调试环境 没有IDE真的蛮难受的 安装插件TASM/MASM 右键扩展设置&#xff0c;选择Assembler&#xff1a;MASM 右键调试即可开始 Debug的主要命令 R-查看和修改寄存器 D-查看内存单元 E-修改内…