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

news2024/9/30 11:31:40

作者推荐

视频算法专题

本文涉及知识点

数学 回溯 字符串 性能优化

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++**实现。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Postman如何进行接口测试简单详细操作实例】

1、下载Postman postman下载地址&#xff1a;Download Postman | Get Started for Free 2、安装Postman (1)双击下载好的postman-setup.exe文件&#xff0c;进行安装postman工具 (2)安装完成后&#xff0c;在桌面找到并打开postman软件&#xff0c;输入邮箱和密码进行登录&a…

微软正在改进其AI驱动的Copilot在Microsoft Teams中的工作方式,为会议聊天、总结等引入了新的召唤助手方式

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

【学习心得】Jupyter常用操作与魔法方法

一、安装与打开 Jupyter是什么我就不啰嗦了&#xff0c;直接安装&#xff1a; pip install jupyter 安装完后&#xff0c;在你想要打开的项目路径下&#xff0c;唤出CMD执行下面命令就可以使用jupyter notebook了 jupyter notebook 也可以用更加好用的jupyter lab&#xff0…

【CXL协议-RAS(12)】

前言&#xff1a; 在了解本章之前&#xff0c;咱们先来了解一下什么是RAS RAS是可靠性&#xff08;Reliability&#xff09;、可用性&#xff08;Availability&#xff09;和服务性&#xff08;Serviceability&#xff09;的缩写&#xff0c;这是衡量系统设计和架构质量的关键…

STM32启动文件命名方式说明以及启动过程分析

1、启动文件的路径 cl&#xff1a;互联型产品&#xff0c;stm32f105/107系列 vl&#xff1a;超值型产品&#xff0c;stm32f100系列 xl&#xff1a;超高密度产品&#xff0c;stm32f101/103系列 flash容量大小&#xff1a; ld&#xff1a;小容量产品&#xff0c; 小于64KB md…

科普 | Runes 预挖矿概念

作者&#xff1a;Jacky X/推&#xff1a;zxl2102492 关于 Runes 协议的前世今生&#xff0c;可以点击阅读这篇文章 &#x1f447; 《简述 Runes 协议、发展历程及最新的「公开铭刻」发行机制的拓展讨论》 什么是传统预挖矿概念 这轮比特币生态爆发之前&#xff0c;预挖矿&…

最优算法100例之08-数组中重复出现一次的数

专栏主页:计算机专业基础知识总结(适用于期末复习考研刷题求职面试)系列文章https://blog.csdn.net/seeker1994/category_12585732.html 题目描述 在一个长度为n的数组里的所有数字都在0到n-1的范围内,数组中只有一个数字重复1次,其他数字都不重复,求出这个数。…

使用IDEA的反编译插件 反编译jar包

反编译插件介绍 安装IDEA后, 一般自带反编译插件, Java Bytecode Decompiler 如果没有可以自己安装下 1.首先找到插件的jar包, 在IDEA安装目录的plugins文件夹下 D:\IntelliJ IDEA 2021.2.2\plugins\java-decompiler\lib 2.运行java命令, 指定插件的jar包目录和你要反编译的ja…

计算机网络:物理层 - 信道复用

计算机网络&#xff1a;物理层 - 信道复用 频分复用时分复用统计时分复用波分复用码分复用 计算机网络中&#xff0c;用户之间通过信道进行通信&#xff0c;但是信道是有限的&#xff0c;想要提高网络的效率&#xff0c;就需要提高信道的利用效率。因此计算机网络中普遍采用信道…

stable diffusion 的 GPU 不足怎么解决

稳定扩散&#xff08;stable diffusion&#xff09;是一种用于图像处理和计算机视觉任务的图像滤波算法。 当使用Stable Diffusion过程中遇到GPU显示内存不足的问题时。解决这个问题的方法有以下几种&#xff1a; 目前&#xff0c;对我来说&#xff0c;就最后一点能够暂时解决当…

2024年腾讯云4核8G服务器多少钱一年?买1年送3个月

2024年腾讯云4核8G服务器租用优惠价格&#xff1a;轻量应用服务器4核8G12M带宽646元15个月&#xff0c;CVM云服务器S5实例优惠价格1437.24元买一年送3个月&#xff0c;腾讯云4核8G服务器活动页面 txybk.com/go/txy 活动链接打开如下图&#xff1a; 腾讯云4核8G服务器优惠价格 轻…

策略路由-IP-Link-路由协议简介

策略路由 策略路由和路由策略的不同 1.策略路由的操作对象是数据包&#xff0c;在路由表已经产生的情况下&#xff0c;不按照路由表进行转发&#xff0c;而是根据需要&#xff0c;依照某种策略改变数据包的转发路径 2.路由策略的操作对象是路由信息。路由策略的主要实现了路…

云电脑安全性怎么样?企业如何选择安全的云电脑

云电脑在保障企业数字资产安全方面&#xff0c;采取了一系列严谨而全面的措施。随着企业对于数字化转型的深入推进&#xff0c;数字资产的安全问题日益凸显&#xff0c;而云电脑作为一种新兴的办公模式&#xff0c;正是为解决这一问题而生。云电脑安全吗&#xff1f;可以放心使…

[BT]BUUCTF刷题第9天(3.27)

第9天&#xff08;共2题&#xff09; [护网杯 2018]easy_tornado 打开网站就是三个txt文件 /flag.txt flag in /fllllllllllllag/welcome.txt render/hints.txt md5(cookie_secretmd5(filename))当点进flag.txt时&#xff0c;url变为 http://b9e52e06-e591-46ad-953e-7e8c5f…

南网科研院携手百度智能云,入选信通院AI原生应用优秀案例

为呈现AI原生研发和应用成效&#xff0c;提供AI原生相关技术、服务、部署、运营、基础设施等选型参考&#xff0c;近期&#xff0c;中国信息通信研究院发布了AI原生技术及应用优秀案例&#xff0c;由南方电网公司输配电部牵头、南方电网科学研究院有限责任公司&#xff08;以下…

Java基础(概念,环境,包,IDEA,)

目录 什么是Java 什么是程序 Java简史 Java技术体系平台 Java语言的特点 搭建环境 搭建Java开发环境 理解三个核心概念 安装Java环境 配置环境变量 编写第一段代码&#xff1a;HelloWorld 创建源代码文件 编写代码 保存文件 编译Java程序 运行程序 查看输出 编…

未能加载文件或程序集socutdata或它的某一个依赖项试图加载格式不正确的程序

未能加载文件或程序集socut data或它的某一个依赖项试图加载格式不正确的程序 Socut.Data.dll找不到类型或命名空间名称 把bin目录下面 的socut.data.dll删除就行了 C#报错未能加载文件或程序集socut data或它的某一个依赖项试图加载格式不正确的程序 "/"应用程序…

数据结构——排序算法

1、排序的概念 排序是指的是将一组数据&#xff08;如数字、单词、记录等&#xff09;按照某种特定的顺序&#xff08;升序或降序&#xff09;进行排列的过程。排序算法是实现排序的程序或方法&#xff0c;它们在软件开发和数据处理中扮演着至关重要的角色。 排序算法可以根据…

Spring Boot 使用过滤器、拦截器、监听器

前言 作用 过滤器&#xff08;Filter&#xff09;&#xff1a;当有一堆请求&#xff0c;只希望符合预期的请求进来。拦截器&#xff08;Interceptor&#xff09;&#xff1a;想要干涉预期的请求。监听器&#xff08;Listener&#xff09;&#xff1a;想要监听这些请求具体做了…

【C++练级之路】【Lv.17】【STL】set类和map类的模拟实现

快乐的流畅&#xff1a;个人主页 个人专栏&#xff1a;《C语言》《数据结构世界》《进击的C》 远方有一堆篝火&#xff0c;在为久候之人燃烧&#xff01; 文章目录 引言一、红黑树&#xff08;改造版&#xff09;1.1 结点1.2 迭代器1.2.1 operator1.2.2 operator- - 1.3 本体1.…