基础算法题——带分数(全排列,工具库)

2023-11-17

前言
这道题理解起来不难,但是要找到一个合适的方法对题目进行优化,就会相对麻烦些。
蓝桥杯的题,真的到处都是坑的感觉。。。

带分数题目

资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
100 可以表示为带分数的形式:100 = 3 + 69258 / 714。
还可以表示为:100 = 82 + 3546 / 197。
注意特征:带分数中,数字1~9分别出现且只出现一次(不包含0)。
类似这样的带分数,100 有 11 种表示法。
输入格式
从标准输入读入一个正整数N (N<1000*1000)
输出格式
程序输出该数字用数码1~9不重复不遗漏地组成带分数表示的全部种数。
注意:不要求输出每个表示,只统计有多少表示法!
样例输入1
100
样例输出1
11
样例输入2
105
样例输出2
6


题目分析

①、带分数中,数字1~9分别出现且只出现一次(不包含0)。
②、100 可以表示为带分数的形式:100 = 3 + 69258 / 714。

解题思路

①:如何实现在带分数中,数字1~9分别出现且只出现一次。我们可以考虑全排列,将每种排列都来一遍(感觉挺麻烦的,如果有更好的方法欢迎留言讨论)。
②:在例子中 100 = 3 + 69258 / 714,“3 + 69258 / 714”部分要符合数字1~9分别出现且只出现一次,这时可以用到我们字符串截取。拿上面的例子说,排列为369258714,我们截取了字符串3、字符串69258、字符串714,然后将三个字符串转换为int类型变量,看看是否符合条件(100 = 3 + 69258 / 714)符合则记录下来。

实用工具功能及使用

实现全排列:next_permutation(s.begin(), s.end());

在C++中,在字符串要有序的前提下,我们能使用现成的函数完成字符串的全排列。例如:string s=“123456789”;,字符串s已经有序。通过 while(next_permutation(s.begin(), s.end())); 不断将s进行全排序,当s的全排序全部排完后,跳出循环。可能你会觉得这个有什么用?让我们带着这个问题看看代码设计吧!

string s="123456789";
do
{
	....
}
while(next_permutation(s.begin(), s.end()));

我们这里用do-while的循环体,保证s每进行一次全排列就会先进行do包含的语句。

实现字符串截取:string a = s.substr(i,len);

在s字符串中,从下标为i的位置,向右截取len长度的字符串,得到a字符串。

实现字符串转换为int类型变量:int a = atoi(s.c_str);

将字符串s转换为int类型变量a。


代码实现

代码一

通过我们的解题思路和工具结合,我们可以得到以下代码一。

//全排列 next_permutation(s.begin(),s.end())
#include<bits/stdc++.h>
#include<time.h>
using namespace std;
#define ll long long
ll ans=0;

int main()
{
//	clock_t start, finish;
//	start = clock();
	int n;
	string s="123456789";
//	sort(s,s+9);
	cin>>n;
	
	do
	{
		for(int i=1; i<=7; i++)
		{
			string a=s.substr(0,i);
			int inta=atoi(a.c_str());
			if(inta>=n) break;
			
			for(int j=1; j<=8-i; j++)
			{
				string b=s.substr(i, j);
				int intb=atoi(b.c_str());
				string c=s.substr(j+i);
				int intc=atoi(c.c_str());
				if(intb%intc==0&&inta+intb/intc==n)
				ans++;
			}
		}
	}
	//使用next_permutation前要先排序  
	while(next_permutation(s.begin(), s.end()));
	cout<<ans;
//	finish = clock();
//	double _time = (double)(finish - start) / CLOCKS_PER_SEC;
//	printf("\ntime:%llf", _time);
	return 0;
}

好啦,恭喜你答对了题目一半,为什么是一半呢?因为如果你拿去评测的话, 你会发现:运行超时!
下面是代码二在N=100条件下的运行时间time (单位秒)
代码一运行时间
原因:substr函数返回的是值(而不是引用或指针) 在多次调用中传递了大量对象(而不是引用或指针) 导致了耗时多
在代码里,substr函数被放在内层循环中,被调用的次数很多,这样的对程序运行总时间的影响就增大了,拖慢了程序运行速度。

代码二(手写截取字符串,引用字符串s)
#include<bits/stdc++.h>
#include<time.h>
using namespace std;
#define ll long long
ll ans=0;

int parse(string &s, int a, int b)//字符串转换为int类型 
{
	int temp=0;
	for(int i=a; i<b; i++)
	{
		temp+=s[i]-'0';
		if(i<b-1)
			temp*=10;
	}
	return temp;
}

int main()
{
//	clock_t start, finish;
//	start = clock();
	int N;
	string s="123456789";
//	sort(s,s+9);
	cin>>N; 
	
	do
	{//	1234567+8/9 
		for(int i=1; i<=7; i++)			//分割第一个数据长度 
		{
			int inta = parse(s, 0, i);
			if(inta>N) break;
			//1+2345678/9
			//12+345678/9 
			//1+2/3456789
			for(int j=1; j<=8-i; j++)		//分割第二个数据长度
			{
				int intb=parse(s, i, j+i);
				int intc=parse(s, j+i, s.length());//分割第三个数据
				if(intb%intc==0&&inta+intb/intc==N)
				{
//					cout<<inta<<"+"<<intb<<"/"<<intc<<endl;
					ans++;
				}
			}
		} 
	}
	while(next_permutation(s.begin(), s.end()));
	cout<<ans;
//	finish = clock();
//	double _time = (double)(finish - start) / CLOCKS_PER_SEC;
//	printf("\ntime:%llf", _time);
	return 0;
}

优化:截取字符串函数传参采用传指针或引用(即在parse 的string参数右侧加一个&)。
下面是代码二在N=100条件下的运行时间time (单位秒)
代码二运行结果
时间上满足1s内,可以通过评测。
下面还能够再通过优化算法的方式,进一步缩短运行时间。

代码三(算法优化)
#include<bits/stdc++.h>
#include<time.h>
using namespace std;
#define ll long long
ll ans=0;

int parse(string& s, int a, int b)//字符串转换为int类型 
{
	int temp=0;
	for(int i=a; i<b; i++)
	{
		temp+=s[i]-'0';
		if(i<b-1)
			temp*=10;
	}
	return temp;
}

int main()
{
//	clock_t start, finish;
//	start = clock();
	int N;
	string s="123456789";
//	sort(s,s+9);
//	N=100;
	cin>>N;
	
	do
	{
		for(int i=1; i<=7; i++)			
		{
			int inta = parse(s, 0, i);
			if(inta>N) break;
			//1+2345678/9
			//12+345678/9 
			//1+2/3456789
			for(int j=1; j<=8-i; j++)	
			{
				if(j<9-i-j) continue;	//排除多余情况
				int intb=parse(s, i, j+i);
				int intc=parse(s, j+i, s.length());
				if(intb%intc==0&&inta+intb/intc==N)
				{
//					cout<<inta<<"+"<<intb<<"/"<<intc<<endl;
					ans++;
				}
			}
		} 
	}
	while(next_permutation(s.begin(), s.end()));
	cout<<ans;
	
//	finish = clock();
//	double _time = (double)(finish - start) / CLOCKS_PER_SEC;
//	printf("\ntime:%llf", _time);
	return 0;
}

优化:排除多余判断情况。
下面是代码三在N=100条件下的运行时间time(单位秒)
运行时间

总结

这道题思路固然重要,但是优化也很重要。
在蓝桥杯的比赛中,都是提交代码,我们不能都提前判断我们的代码是否能够通过所有评测数据,所以要尽量将时间复杂度降到最小。

感谢评论区的朋友,对我的文章提出指正√
希望能够将自己的一些学习经验分享给有需要的人。
我是小郑,一个坚持不懈的小白。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基础算法题——带分数(全排列,工具库) 的相关文章

随机推荐

  • QT找不到依赖库的解决办法

    QtCreator打开例程后 需要切换到 项目 页面 手动去掉勾选Shadow build 否则自动生成的构件目录里找不到依赖文件 编译出错
  • 230. Kth Smallest Element in a BST

    查找二叉搜索树的第K小节点 利用bst的中序遍历的性质 bst 中序遍历可以得到一个有序数组 每次从stack中弹出一个元素 看k 进行计数即可 Inorder Traversal We can inorder traverse the t
  • Spring系列文章:Spring中的设计模式

    一 简单 模式 BeanFactory的getBean 法 通过唯 标识来获取Bean对象 是典型的简单 模式 静态 模 式 二 法模式 FactoryBean是典型的 法模式 在配置 件中通过factory method属性来指定 法 该
  • Mac使用bootcamp安装win系统花屏解决方法

    15年11 乞丐版air装win屏幕花屏 很郁闷 先后找了网上很多方法 最终总结出了一个比较折中的方法 不玩游戏不使用大型3D的可以参考 1 花屏现象 2 解决方法 2 1 禁用驱动 2 2 使用Microsoft基本显示适配器 2 2 1
  • 记 asp.net core 开发过程中的错误

    mysql数据库 ef进行 update database 时 报 An error occurred using the connection to database on server localhost 3307 错误原因 serve
  • ctf.show web入门

    目录 信息收集 web1 where is flag web2 无法查看源代码 web3 where is flag web4 robots web5 phps文件泄露 web6 网站源码泄露 web7 git web8 svn泄露 web
  • 使用 OpenCV 和 Tesseract 对图像中的感兴趣区域 (ROI) 进行 OCR

    点击上方 小白学视觉 选择加 星标 或 置顶 重磅干货 第一时间送达 在这篇文章中 我们将使用 OpenCV 在图像的选定区域上应用 OCR 在本篇文章结束时 我们将能够对输入图像应用自动方向校正 选择感兴趣的区域并将OCR 应用到所选区域
  • tensorrt和onnxruntime-gpu同时调用gpu时tensorrt推理出现错乱解决方式

    问题 当我在同一个进程同时调用tensorrt和onnxruntime gpu时 出现了tensorrt推理结果全为0的情况 解决方式 将onnxruntime gpu放到cpu上 但是cpu的推理速度明显会不如gpu 如果在python中
  • 深度剖析数据在内存中的存储(修炼内力)

    目录 一 数据类型的介绍 1 1数据大小 1 2类型的基本归类 二 整型在内存中的存储 2 1原码 反码 补码 2 2大小端介绍 2 2 1大小端的起源 2 2 2大小端的概念 2 2 3为什么会有大端和小端 2 2 4设计一个小程序来判断
  • Fedora 启动顺序

    http hi baidu com wwwkljoel item 29620217882a585b2b3e2244 The start of the Fedora fedora 系统加电或复位后 中央处理器将内存中的所有数据清零 并对内存进
  • html往下滑变成水平,HTML - 水平滑块CSS最佳方法_html_开发99编程知识库

    由於每個部分的位置已經設置為relative 意味著將relative定位到上一節 因此可以將其他部分設置為left 0 margin 0 all sections display inline flex main about profes
  • 【学】saas系统前端技术选型,需要考虑哪些方面?

    对于saas前端技术选型 可以考虑以下几个方面 框架选择 目前比较流行的前端框架有React Vue Angular等 可以根据项目需求和团队技术水平选择合适的框架 例如 如果需要高度可定制性和灵活性 可以选择React 如果需要快速开发和
  • 数学建模之灰色关联实例含代码

    参考书籍 数学建模算法与应用 一 预备 1 无量纲化处理技术 二 灰色关联的步骤 通过对某健将级女子铅球运动员的跟踪调查 获得其 1982 年至 1986 年每年好成绩及16 项专项素质和身体素质的时间序列资料 见表 2 试对此铅球运动员的
  • linux-UNIX socket

    UNIX域套接字 域套接字作为进程间通信的一种手段 值得我们研究一下 域套接字实现本地进程间通信 同样有服务端和客户端之分 一个进程作为客户端 另一个进程作为服务端 这个和TCP socket类似 但是不一样 域套接字不经过底层网络 数据结
  • LaTeX 数学公式大全!

    LaTeX 数学公式大全 这里是来自一篇教程的截图 很全面
  • java.util之ArrayList使用

    java util之ArrayList使用 一 概述 ArrayList底层实际是通过一个数组来保存数据 其默认大小为10 扩容机制为新的容量 原始容量x3 2 1 允许空值 有序 为线程不安全 可以使用迭代器遍历 里面的的元素全部都是对象
  • NoteExpress安装时问题解决

    每次安装软件我都不能一次性成功 这次遇见的是NoteExpress和Word权限不一致的问题 版本 win10 office2019 网上有很多方法 其中CSDN博主 令令狐大侠 总结郭一篇 原文链接 https blog csdn net
  • 【华为OD机试】工号不够用了怎么办 (C++ Python Java)2023 B卷

    题目描述 3020年 空间通信集团的员工人数突破20亿人 即将遇到现有工号不够用的窘境 现在 请你负责调研新工号系统 继承历史传统 新的工号系统由小写英文字母 a z 和数字 0 9 两部分构成 新工号由一段英文字母开头 之后跟随一段数字
  • 关于split截取字符时,问号的特殊情况

    有一段字符 tring str gjjxxcx gjjxx cx jsp zgzh 1010024000019 如果使用如下代码 String strArray str split gjjxx cx jsp System out print
  • 基础算法题——带分数(全排列,工具库)

    前言 这道题理解起来不难 但是要找到一个合适的方法对题目进行优化 就会相对麻烦些 蓝桥杯的题 真的到处都是坑的感觉 带分数题目 资源限制 时间限制 1 0s 内存限制 256 0MB 问题描述 100 可以表示为带分数的形式 100 3 6