第十届蓝桥杯省赛题:把 2019 分解成 3 个各不相同的正整数之和,并且要求每个正整数都不包含数字 2 和 4,一共有多少种不同的分解方法?
题目
【问题描述】
把 2019 分解成 3 个各不相同的正整数之和,并且要求每个正整数都不包含数字 2 和 4,一共有多少种不同的分解方法?注意交换 3 个整数的顺序被视为同一种方法,例如 1000+1001+18 和1001+1000+18 被视为同一种。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
我的思路
本人初步接触蓝桥杯的算法题,也没系统研究过同类题型,只是简单分享下自己的做题感悟。第一次发布博文,欢迎大家批评指正!
- 初步想法还是选择直接暴力拆分 ,于是考虑最大限度减少循环次数;
- 原理是以第一个数为三个数中最小的数依次向后遍历,遍历次数需要总数2019的三分之一即可,这里设第一个数为 i;
- 确定完第一个数之后,再以第二个数为剩下两个数中最小的数依次向后遍历,遍历次数需要 2019 - i 的二分之一即可,这里设第二个数为 j,第三个数为 k;
- 题目要求交换顺序的三个正整数不算数,于是考虑将这三个数直接从小到大排列之后再存储到结果集;
- 受上一个题计算子字符串个数的启发,我选用了HashMap存储结果集,存储思想就是把这三个数排序之后用+号连接转为字符串存入Map,这样可以直接避免重复值;
- 最后,打印出Map的size即可;
上代码
public void testInt(){
int int0 = 2019;
HashMap map = new HashMap();
for(int i = 1;i<=(int0/3);i++){//其实第一个数遍历到2019的三分之一即可
if( Integer.toString(i).contains("2") || Integer.toString(i).contains("4") ){
continue; //如果第一个数包含2或4则直接不考虑
}
for(int j = 1;j<=((int0-i)/2);j++){//其实第二个数遍历到2019-i的二分之一即可
if( Integer.toString(j).contains("2") || Integer.toString(j).contains("4") ){
continue; //如果第二个数包含2或4则直接不考虑
}
int k = int0-i-j;
if( Integer.toString(k).contains("2") || Integer.toString(k).contains("4") ){
continue; //如果第三个数包含2或4则直接不考虑
}
//将三个数值按从小到大排列
//sortThree方法就是把三个数从小到大排一下然后中间用+号连接成字符串
map.put(sortThree(i,j,k),0);
}
}
System.out.println(map.size());
}
于是乎,程序的输出是
我还挺高兴,但是查阅了好几个网上的大佬给出的结果都是40785…
草率了,把41087个结果打印出来挨个检查!
添加代码段输出Map中的值:
Set<Map.Entry<String,Integer>>set = map.entrySet();
for(Map.Entry<String ,Integer>entry : set){
System.out.println(entry.getKey());
}
System.out.println(map.size());
输出如下:
为了验证每条结果是否重复或结果不为2019的情况,我把所有数据放到了Excel里(乱入):
首先编辑公式
选择填充范围
向下填充公式
A列添加条件格式:重复值标红—>>添加筛选条件:按颜色筛选 ,B列按升序排序
得到如下结果:
结果为A列无重复值且结果均为2019…
这波大意了?!
于是乎又审了遍题目,淦!三个不同正整数的和??
改代码!
public void testInt(){
int int0 = 2019;
HashMap map = new HashMap();
for(int i = 1;i<=(int0/3);i++){//其实第一个数遍历到2019的三分之一即可
if( Integer.toString(i).contains("2") || Integer.toString(i).contains("4") ){
continue; //如果第一个数包含2或4则直接不考虑
}
for(int j = 1;j<=((int0-i)/2);j++){//其实第二个数遍历到2019-i的二分之一即可
if( Integer.toString(j).contains("2") || Integer.toString(j).contains("4") || i==j){
continue; //如果第二个数包含2或4,或者前两个数相同,则直接不考虑
}
int k = int0-i-j;
if( Integer.toString(k).contains("2") || Integer.toString(k).contains("4") || i==k || j==k){
continue; //如果第三个数包含2或4,或者一三数相同或二三数相同,则直接不考虑
}
//将三个数值按从小到大排列
//sortThree方法就是把三个数从小到大排一下然后中间用+号连接成字符串
map.put(sortThree(i,j,k),0);
}
}
System.out.println(map.size());
}
此处添加了判断三个数中是否含相等值的条件
结果如下:
好的,这波可以安心的继续脱发了。
心得体会
现在还在考虑要不要参加蓝桥杯比赛,编了几道题也大概了解了些比赛时候的一点注意事项,那就是一定要冷静,然后认真审题!