蓝桥杯练习题四 - 排它平方数(c++)

简介: 蓝桥杯练习题四 - 排它平方数(c++)

题目如下


203879 * 203879 = 41566646641


这有什么神奇呢?仔细观察,203879 是个6位数,并且它的每个数位上的数字都是不同的,并且它平方后的所有数位上都不出现组成它自身的数字。


具有这样特点的6位数还有一个,请你找出它!


再归纳一下筛选要求:


1、6位正整数

2、每个数位上的数字不同

3、其平方数的每个数位不含原数字的任何组成数位


以下程序实现了这一功能,请你补全以下空白处内容:

#include <iostream>
using namespace std;
int main()
{
    int num[10], flag;
    for (long long i = 123456; i <= 987654; i++)
    {
        long long a = i;
        long long b = i * i;
        memset(num, 0, sizeof(num));
        flag = 1;
        while (a)
        {
            _________________;
        }
        if (flag)
        {
            while (b)
            {
                if (num[b % 10])
                {
                    flag = 0;
                    break;
                }
                b /= 10;
            }
            if (flag)
                cout << i << endl;
        }
    }
    return 0;
}

提示:

0的平方为0
1的平方为1
5的平方为5
6的平方为6
以上这4个数字都不能作为原数字的最后一位,可以在最后一位排除
且第一位不能为0

最终代码如下:

#include <iostream>
using namespace std;
int main()
{
    int num[10], flag;
    for (long long i = 123456; i <= 987654; i++)
    {
        long long a = i;
        long long b = i * i;
        memset(num, 0, sizeof(num));
        flag = 1;
        while (a)
        {
            if (num[a % 10])
            {
                flag = 0;
                break;
            }
            num[a % 10]++ 
            a /= 10;
        }
        if (flag)
        {
            while (b)
            {
                if (num[b % 10])
                {
                    flag = 0;
                    break;
                }
                b /= 10;
            }
            if (flag)
                cout << i << endl;
        }
    }
    return 0;
}

解析如下:


1.for (long long i = 123456; i <= 987654; i++)


i的起始值和结束值,起始值应该为最小的不重复的数字,结束值应该为最大的不重复的数字,有些人代码直接就写成了起始值为100000,结束值为999999,这样也行,只不过会增加运算的次数,但这里给出的123456明显也不太符合六位数不重复且最小值的定义,我认为应该是102345,这个才是最小值。


2.memset(num, 0, sizeof(num));


memset:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法。


这条语句是把num中中所有字节换做字符“0”,常用来对指针或字符串的初始化。


sizeof可设置从0开始的长num的替换区间,但必须从第0位开始,同时0也可以替换成其他的字符。


3.第一个while循环


//

while (a)
{
    if (num[a % 10])
    {
        flag = 0;
        break;
    }
    num[a % 10]++ 
    a /= 10;
}

全篇最难理解的来了,大家要认真仔细的看了。


while(a)不难理解,a不为0

num[a % 10]这个有点难理解了,需要上道具,结合2中的memset来说明,memset(num, 0, sizeof(num));之后,num是下面这样的:

num = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];

a % 10是什么呢?假设a为123456,a % 10 = 6,num[6]是多少呢?num是个数组,里面全是0,num[6] = 0,此时if (num[a % 10])就是if(0),条件不成立,num[a % 10]++,它等价于num[6]++,num[6]是0,num[6]++后就是1,这时的num是多少呢?看下面:

num = [0, 0, 0, 0, 0, 0, 1, 0, 0, 0];

以上是第一次循环,之后,a /= 10,a = 12345, 我们继续:


第二次循环时if里面是num[5],num[5]是0,条件不成立,num[5]++,num[5]是0,num[5]++后就是1,这时的num是多少呢?看下面:

num = [0, 0, 0, 0, 0, 1, 1, 0, 0, 0];

此时,a /= 10,a = 1234, 我们继续:


第三次循环时if里面是num[4],num[4]是0,条件不成立,num[4]++,num[4]是0,num[4]++后就是1,这时的num是多少呢?看下面:

num = [0, 0, 0, 0, 1, 1, 1, 0, 0, 0];

此时,a /= 10,a = 123, 我们继续:


第四次循环时if里面是num[3],num[3]是0,条件不成立,num[3]++,num[3]是0,num[3]++后就是1,这时的num是多少呢?看下面:

num = [0, 0, 0, 1, 1, 1, 1, 0, 0, 0];

此时,a /= 10,a = 12, 我们继续:


第五次循环时if里面是num[2],num[2]是0,条件不成立,num[2]++,num[2]是0,num[2]++后就是1,这时的num是多少呢?看下面:

num = [0, 0, 1, 1, 1, 1, 1, 0, 0, 0];

此时,a /= 10,a = 1, 我们继续:


第六次循环时if里面是num[1],num[1]是0,条件不成立,num[1]++,num[1]是0,num[1]++后就是1,这时的num是多少呢?看下面:

num = [0, 1, 1, 1, 1, 1, 1, 0, 0, 0];

此时,a /= 10,a = 0, 继续


这时候while(a)条件不成立,直接走到下面去了。


这里解释下为什么要这么做:


它的每个数位上的数字都是不同的,并且它平方后的所有数位上都不出现组成它自身的数字


注意这段话,数字每一位不重复,平方后每一位数字和平方前不重复。


我们得到了满足条件的a之后,就可以用和a同样的方式来在num中取值,如果取出来不为0,则说明b和a重了,那么这个a就不满足题目中我们需要的答案。


如果a中数字重复,那么直接就进入if中执行,flag=0,也就没有后面b啥事了。


4.flag中第二个for循环


if (flag)
{
    while (b)
    {
        if (num[b % 10])
        {
            flag = 0;
            break;
        }
        b /= 10;
    }
    if (flag)
        cout << i << endl;
}

a满足条件,flag就不会变为0,进入i+1的下一个for循环。


有没有发现两个for循环特别的像?没错,几乎一样,注意,这里要敲黑板了,很重要的一点:


第二个for循环中只通过num[b % 10]去取值,但是没有进行赋值操作,也就是第一个for循环中num[a % 10]++的操作,这里只做了取值来判断num中对应的数字下标位置是否有值,有值,说明重复,flag=0,跳出循环,继续下一个值,没有值,说明不重复,直到验证完每一位的值之后,输出i。


每一次的循环和3里面是一样的,只是没有num的赋值操作,只做了效验,博主就不再赘述了,能耐心看到这里,恭喜你,相信你已经基本掌握了排它平方数。


5.提示内容


0的平方为0
1的平方为1
5的平方为5
6的平方为6
以上这4个数字都不能作为原数字的最后一位,可以在最后一位排除
且第一位不能为0

这个不可不看,关系到效率问题,可以在for循环中提前判断最后一位数是不是提示中存在的数字,可直接跳过,可以减少绝大部分无效运算,提高程序的运行效率,所以,把下面这段代码加进for循环中,最先执行。

if (i % 10 == 1 || i % 10 == 5 || i % 10 == 6 || i % 10 == 0) 
{
    continue;
}

到这里,也到了跟大家说再见的时候,分析完了,有问题,欢迎评论区留言讨论,咱们下篇再见。

目录
相关文章
|
2月前
|
算法 测试技术 C++
【动态规划算法】蓝桥杯填充问题(C/C++)
【动态规划算法】蓝桥杯填充问题(C/C++)
|
2月前
|
人工智能 算法 BI
第十四届蓝桥杯省赛大学C组(C/C++)三国游戏
第十四届蓝桥杯省赛大学C组(C/C++)三国游戏
|
2月前
|
人工智能 C++
第十四届蓝桥杯省赛大学B组(C/C++)整数删除
第十四届蓝桥杯省赛大学B组(C/C++)整数删除
|
7月前
|
网络安全
蓝桥杯-网络安全-练习题-crypto-rsa
蓝桥杯-网络安全-练习题-crypto-rsa
蓝桥杯-网络安全-练习题-crypto-rsa
|
2月前
|
机器学习/深度学习 算法 关系型数据库
第十五届蓝桥杯C++B组省赛
第十五届蓝桥杯C++B组省赛
113 14
|
2月前
|
算法 C++
2022年第十三届蓝桥杯大赛C/C++语言B组省赛题解
2022年第十三届蓝桥杯大赛C/C++语言B组省赛题解
53 5
|
7月前
|
算法 测试技术 C++
小唐开始刷蓝桥(八)2013年第四届C/C++ B组蓝桥杯省赛真题
小唐开始刷蓝桥(八)2013年第四届C/C++ B组蓝桥杯省赛真题
|
7月前
|
算法 C++ 数据格式
小唐开始刷蓝桥(七)2014年第五届C/C++ B组蓝桥杯省赛真题
小唐开始刷蓝桥(七)2014年第五届C/C++ B组蓝桥杯省赛真题
|
7月前
|
算法 C++
小唐开始刷蓝桥(五)2016年第七届C/C++ B组蓝桥杯省赛真题
小唐开始刷蓝桥(五)2016年第七届C/C++ B组蓝桥杯省赛真题
|
7月前
|
算法 C++
小唐开始刷蓝桥(六)2015年第六届C/C++ B组蓝桥杯省赛真题
小唐开始刷蓝桥(六)2015年第六届C/C++ B组蓝桥杯省赛真题