题目如下:
本题要求你编程解决一个更通用的问题:从任一给定的长度为 L 的数字中,找出最早出现的 K 位连续数字所组成的素数。
输入格式:
输入在第一行给出 2 个正整数,分别是 L(不超过 1000 的正整数,为数字长度)和 K(小于 10 的正整数)。接下来一行给出一个长度为 L 的正整数 N。
输出格式:
在一行中输出 N 中最早出现的 K 位连续数字所组成的素数。如果这样的素数不存在,则输出 404。注意,原始数字中的前导零也计算在位数之内。例如在 200236 中找 4 位素数,0023 算是解;但第一位 2 不能被当成 0002 输出,因为在原始数字中不存在这个 2 的前导零。
输入样例 1:
20 5
23654987725541023819
输出样例 1:
49877
输入样例 2:
10 3
2468024680
输出样例 2:
404
解决方法:
1.思路:
(1)要处理的数据是一个长度不超过1000位的正整数,很明显,应该使用字符串来存取这个数据。
(2)既然需要输出的是最早出现的由K位数字组成的素数,那么首先就应该先把这些K位数字组成的数找出来,接着从这些数中找到第一个出现的素数,最后输出。
有了思路,就只需要解决用字符串存储数据,寻找K位数字组成的数,判断是否为素数这三个主要问题就可以解出这个题。
2.使用字符串存取数据:
当整数的位数很大时,就应该使用字符串来存取数据了,将每一位数字都存入一个字符串数组元素中,如果题目需要使用int型数据的时候,将字符型数据减去0对应的ASCII码值即可得到整型数值(即 - ’ 0 ')。
3.寻找K位数字:
如果对C++不是很熟悉的话,那么就应该老老实实的使用双层循环来实现找到K位数字的数。
如下:
//len为整数的长度,m为连续K位数字的位数K
for(int i = 0; i < len - m + 1; i++)
{
for(int j = i; j < i + m; j++) {}
}
外层循环的作用是使得循环从第一位开始到第len - m + 1位结束,内层循环的作用则是由第i位开始连续取m位数字。按照题目的例子来说:
20 5
23654987725541023819
len是20,m是5,那么这些数字就应该从第一位2开始,连续5位数字:23654,接着到3,连续5位数字:36549,接着65498…一直到第16位2开始的五位数字23819。特别的要注意这里是第16位数字截止的而不是第15位数字截止。这就是外循环上限是len - m + 1的原因。
如果对C++很熟悉的话,C++的string类中有个函数substr,可以实现以上功能。
substr:
- 用途:一种构造string的方法
- 形式:s.substr(pos, n)
- 解释:返回一个string,包含s中从pos开始的n个字符的拷贝(pos的默认值是0,n的默认值是s.size() - pos,即不加参数会默认拷贝整个s)
- 补充:若pos的值超过了string的大小,则substr函数会抛出一个out_of_range异常;若pos+n的值超过了string的大小,则substr会调整n的值,只拷贝到string的末尾
#include<string>
#include<iostream>
using namespace std;
int main()
{
string s("12345asdf");
string a = s.substr(0,5); //获得字符串s中从第0位开始的长度为5的字符串
cout << a << endl;
}
//输出结果为:12345
虽然现在已经将数字找出来了,可是这个数字目前还是字符串类型的,并不是整型,所以接着必须把他们变成整型,因为保存数字用的是字符串数组,将字符串数组的每一位减去0的ASCII码值即可得到这个数字,然而题目要求的是连续数字,所以需要把他们加起来,这时就需要用到函数pow,利用pow得到10的幂次方,将10的幂次方对应个十百千位相乘再相加,就得到了数字(例如23654 = 20000 + 3000 + 600 + 50 + 4)。如果觉得以上方法繁琐的话,可以使用C++函数atoi,直接就可以将string类型转换为int类型。
按照以上思路,就可以写代码了:
int sum[n - m + 1] = {0};
//首先创立一个数组来保存得到的数字,这个数组的大小应该和外循环的上限是一样的。
int flag;
//因为需要实现10的幂次方的降幂,所以需要一个变量来控制幂次
int number;
//最后将string类型的数据减去ASCII码值后得到的整数赋值给number,由他来进行相关的计算。
//第一步得到string字符串的长度
int len = str.length();
//第二步开始循环
for(int i = 0; i < len - m + 1; i++) {
//首先给10的幂次设定上限,因为是m位数,所以高位肯定是10的m - 1次方
flag = m - 1;
for(int j = i; j < i + m; j++) {
number = str[j] - '0';
sum[i] += number * pow(10, flag);
flag--;
}
}
或者是:
for(int i = 0; i < len - m + 1;i++) {
int number;
string s=str.substr(i,K);
number=atoi(s.c_str());
}
4.判断素数
通过判断n能否被从2到根号n中的任何一个整数整除来判断是否为素数
bool isPrime(int n)
{
if(n <= 1) return false;
int sqr = sqrt(1.0 * n);
for(int i = 2; i <= sqr; i++){
if(n % i == 0) return false;
}
return true;
}
完整代码:
#include <iostream>
#include <algorithm>
#include <math.h>
#include <iomanip>
using namespace std;
bool isPrime(int n)
{
if(n <= 1) return false;
int sqr = sqrt(1.0 * n);
for(int i = 2; i <= sqr; i++){
if(n % i == 0) return false;
}
return true;
}
int main()
{
string str;
int n,m;
cin >> n >> m;
cin >> str;
int sum[n - m + 1] = {0};
int flag;
int number;
int times = 0;
int len = str.length();
for(int i = 0; i < len - m + 1; i++) {
flag = m - 1;
for(int j = i; j < i + m; j++) {
number = str[j] - '0';
sum[i] += number * pow(10, flag);
flag--;
}
}
for(int i = 0; i < len - m + 1; i++) {
if(isPrime(sum[i]) == true) {
cout << setfill('0') << setw(m) << sum[i] << endl;//前面自动补0
times++;
break;
}
}
if(times == 0) cout << "404";
return 0;
}