快捷搜索:

【蓝桥真题1】这道用了7个for循环的蓝桥真题,让舍友哭着跑出考场【内附原题资源】

📒博客首页: ❤️ :热爱Java学习,期待一起交流! 🌺有问题可私信交流!!!

🍋1.蓝桥刷题须知

蓝桥杯比赛并不像我们平时在力扣和牛客网刷题一样,对我们代码运行和时间有着限制。Java组采用的是eplipse编译器,C/C++才用的是DevC++。填空题我们需要在编译器中自己跑出答案,然后直接提交答案即可。所以大家不要担心什么啊这个代码难道不会超时吗,这个代码空间复杂度也太大了吧,人家只看你的答案是否正确,就算你把电脑跑烂了都没问题,所以要大胆尝试。

🍋2.经典例题讲解

🚀1.世纪末的星期(经典日期API问题)

题目:有邪教称1999年12月31日是世界末日,当然谣言已经不攻自破。还有人称今后的某个世纪末的12月31日,如果是星期一则会....有趣的是,任何一个世纪末的年份的12月31日都不可能是星期一!!!于是"谣言制造商"又修改为星期日....... 1999年12月31日是星期五,请问:未来哪一个离我们最近的一个世纪末年(即XX99年)的12月31日正好是星期天(即星期日)? 回答年份即可
public class 世纪末的星期 {
    public static void main(String[] args) {
        Calendar calendar = Calendar.getInstance();
        for (int year = 1999; year <10000 ; year+=100) {
            calendar.set(Calendar.YEAR,year);
            calendar.set(Calendar.MONTH,11);//其实是12月
            calendar.set(Calendar.DAY_OF_MONTH,31);
            if (calendar.get(Calendar.DAY_OF_WEEK)==1) {
            //sunday是第一天,所以为1时是Sunday,通过源码查看
                System.out.println(year);// 2299
                break;
            }
        }
    }
}
🔑解析:之所以要讲这道经典例题,是因为日期问题是蓝桥杯的高频考点。Java组在这种题目占尽便宜,因为Java中有着Calendar这个日期API,这是非常重要的。它能几乎解决与日期相关的所有问题。这里我们通过设置年月份,然后判断是否是星期天,如果是则直接输出答案,非常简单。如果这题不使用CalendarAPI的话,还是非常麻烦的,所以Java组的小伙伴一定要学会。

🚀2.马虎的算式(五个for循环枚举问题)

题目:小明是个急性子,上小学的时候经常抄错题目。有一次老师出的36X495=?他却抄成了396X45?但结果却很戏剧性,他的答案是正确的!!因为36 * 495= 396 * 45=17280 类似这样的巧合可能还有很多,比如27 * 594=297 * 54。 假设a b c d e代表1~9不同的五个数字(注意是各不相同的数字,且不含0),能满足 这样的格式的式子总共有多少种?
public class 马虎的算式 {
    public static void main(String[] args) {
        int count=0;
        for (int a = 1; a <= 9; a++) {
            for (int b = 1; b <= 9; b++) { //每次for循环前要判断前面是否有相等元素
                if (a != b) for (int c = 1; c <= 9; c++) {
                    if (b != c && a != c) for (int d = 1; d <= 9; d++) {
                        if (a != d && b != d && c != d) for (int e = 1; e <= 9; e++) {
                            if (a != e && b != e && c != e && d != e) {
                                if ((a * 10 + b) * (c * 100 + d * 10 + e) == (a * 100 + d * 10 + b) * (c * 10 + e)) {
                                        count++;
                                }
                            }
                        }
                    }
                }
            }
        }
        System.out.println(count);//答案为142
    }
}
🔑解析:这是道非常经典的枚举问题,很多人可能会觉得5个for循环这复杂度也太高了吧,但其实每个循环都是常数级,即使放到平时的刷题平台也不会超时。枚举类型的题目,需要大家答案的去实现,枚举当然就是想方设法去列出所有的情况,再判断是否符合题意。蓝桥杯对这种题型是钟爱有加,就是因为大家平时在各种刷题平台对这种题遇到比较少,一下紧张,不敢大胆地实现自己的思路。

🚀3.振兴中华(基础动规问题)

题目:小明参加了学校的趣味运动会,其中的一个项目是:跳格子 地上画着一些格子,每个格子里写一个字;如下图 从我做起振 我做起振兴 做起振兴中 起振兴中华 比赛时从左上角的的"从"字开始,只能横向或纵向跳到相邻的格子里,但不能跳到对角的格子,要求跳到"华"字结束。要求跳过的路线刚好是"从我做起振兴中华"这句话,请问小明有几种可能的跳跃路线
public class 振兴中华 {
    public static void main(String[] args) {
        int[][] arr=new int[4][5];//注意是四列五纵
        for (int i = 0; i < 5; i++) {
            arr[0][i]=1;
        }
        for (int i = 0; i < 4; i++) {
            arr[i][0]=1;
        }
        for (int i = 1; i < 4; i++) {
            for (int j = 1; j < 5; j++) {
                arr[i][j]=arr[i-1][j]+arr[i][j-1];//状态转移方程
            }
        }
        System.out.println(arr[3][4]);//35种
    }
}
🔑解析:这是道很简单的动规问题,当然没学过动规的兄弟会觉得有点难。没学过动规的兄弟建议先从斐波那契数列开始学习动规。动规是蓝桥杯的高频考点之一,它出的动规可能会很难也可能会很简单,所以兄弟们对于简单的动规问题千万不能做错。

🚀4.猜字母(字符处理问题)

题目: 把abcd....s共19个字母组成的序列重复拼接106次,得到长度为2014的串。 接下来删除第1个字母(即开头的字母a),以及第3个,第5个等所有奇数位置的字符。 得到的新串再进行删除奇数位置字母的动作。如此下去,最后只剩下一个字母,请写出该字母。

思路1:采用字符串形式

public class 猜字母 {
    public static void main(String[] args) {
        StringBuilder a=new StringBuilder("abcdefghijklmnopqrs");
        //StringBuilder效率更高
        for (int i = 1; i <106 ; i++) {
            a.append("abcdefghijklmnopqrs");
        }
        //重复拼接获得子串
        while (a.length()>1){  
               int l=a.length()/2;
            if (a.length()%2!=0) {
                l++;
            }
            for (int i = 0; i <l; i++) {//注意这里是i++不是i+=2,因为待删除的数组下标在变化
                a.deleteCharAt(i);
            }
        }
        System.out.println(a);//q
    }
}
🔑解析:首先这里我们用的是StringBuider,因为它的效率是最高的。这里我们才用字符串的一个好处是它自带的delete操作可以帮助我们删除元素,但正因如此也是我们容易掉坑的地方。当我们删除一个元素后,后续的元素会马上排上来,导致我们本该删除的元素的下标变化,导致了删掉了错误的元素。但其实也是有规律的,每删除一个元素后,后续所有待删除的元素都向左移动一格。比如有个字符串abcde,按照要求我们需要删掉ace这三个,a的下标为0删除后,原字符串变为bcde,这时本来下标为2的c变成了1,这时我们删掉c后再下一个待删除的元素e下标变为2了。于是本来需要隔一个再删除,却由于下标动态变化就只需要让i++而不是i+=2了。这里只需要考虑到长度为奇数时需要比偶数多删一次的问题即可,最后删剩的字符就是q。

思路2:采用数组形式

public class 猜字母02 {
    public static void main(String[] args) {
        char[] a=new char[2014];
        int index=0;
        for (int i = 0; i < 106; i++) {
            for (int j = 0; j < 19; j++) {
                a[index++]= (char) (a+j);//这里涉及到ascii表的字母转换
            }
        }
        //采用数组形式存放
        int len=2014;
        while (len!=1){
            int k=0;
            for (int i = 1; i <len ; i+=2) {
                a[k++]=a[i];
            }
            len=k;
        }
        System.out.println(a[0]);//q
    }
}
🔑解析:用数组形式来做的话更好理解也不容易出错。把每次需要留下来的元素往前摆。用len来动态地保存这一段的长度,k是待插入的下标。每次需要保存的元素往前放,然后用len更新保留下来的数组长度,一次次往前移动,不要的元素放数组后面。最后循环结束后,数组的第一个元素就是我们剩下的元素q。

🚀5.立方变自身(简单枚举)

题目:观察下面的现象,某个数字的平方,按位累加仍然等于自身 1^3=1 8^3=512 5+1+2=8 17^3=4913 4+9+1+3=17 ... 请你计算包括1,8,17在内,符合这个性质的正整数一共有多少个?
public class 立方自身 {
    public static void main(String[] args) {
        int count = 0;
         //其实到最多到100就可以了,也可以加大范围枚举,会发现答案不会变多
        for (int i = 1; i < 100; i++) {
            if (sum((int) Math.pow(i, 3)) == i) {
                count++;
            }
        }
        System.out.println(count);//6
    }
    public static int sum(int x){//获得数x各个位相加的返回值
        int count=0;
        while(x>0){
            count+=x%10;
            x=x/10;
        }
        return count;
    }
}
🔑解析:这道题就是普通的枚举题目,它的枚举范围也很好确定。当到100的三次方时,数就已经很大了,即使再往后枚举也不会让答案增多。不过为了更好确定,我们也可以把i的范围拉大继续枚举,会发现答案仍然也只有6个。

🚀6.三羊献瑞(7个for循环枚举问题)

题目: 观察下面的加法算式: 祥 瑞 生 辉 + 三 羊 献 瑞 ———————————— 三 羊 生 瑞 气
public class 三羊祥瑞 {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 10; j++) {
               if (i!=j)for (int k = 0; k < 10; k++) {
                   if (i!=k&&j!=k)for (int l = 0; l < 10; l++) {
                        if (i!=l&&j!=l&&k!=l)for (int m = 0; m < 10; m++) {
                            if (i!=m&&j!=m&&k!=m&&l!=m)for (int n = 0; n < 10; n++) {
                                if (i!=n&&j!=n&&k!=n&&l!=n&&m!=n)for (int o = 0; o < 10; o++) {
                                    if (i!=o&&j!=o&&k!=o&&l!=o&&m!=o&&n!=o){
                                        int x1=i*1000+j*100+k*10+l;
                                        int x2=m*1000+n*100+o*10+j;
                                        if (isOK(x1,x2,i,j,k,l,m,n,o)){
                                            System.out.println(" "+x1);
                                            System.out.println(" "+x2);
                                            System.out.println(x1+x2);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    public static boolean isOK(int x1,int x2,int i,int j,int k,int l,int m,int n,int o){
        int count=x1+x2;
        if (count<10000) return false;//如果加起来不是五位数可以直接返回false
        int a=count%10;
        if (a==i||a==j||a==k||a==l||a==m||a==n||a==o) return false;
        count=count/10;
        a=count%10;
        if (a!=j) return false;
        count=count/10;
        a=count%10;
        if (a!=k) return false;
        count=count/10;
        a=count%10;
        if (a!=n) return false;
        count=count/10;
        a=count%10;
        if (a!=m) return false;
        return true;
    }
}
🔑解析:这是一道非常非常经典的蓝桥真题枚举问题。最直接最暴力的方法就直接去写七个for循环分别将祥瑞生辉三羊献七个字枚举出来,再写一个判断答案是否符合要求的方法。思路很简单,但是步骤写起来需要小心。但其实这里我想说的是这里其实是可以优化的,两个四位数相加得到一个五位数。那么这个这个五位数的万位只可能是1,也就是三字其实就是1,既然祥加三得进位,三又是1,那么祥肯定就只能是9,进而再可得羊是0。大家可以和上面我贴出的答案对比就能看出来。这样其实我们的循环就少了几层了,但蓝桥杯做出答案才是目的,即使是7个for循环,但其实都是常数级的循环,瞬间就可以枚举出结果。

🚀7.加法变乘法(插乘枚举)

题目:
public class 加法变乘法 {
    public static void main(String[] args) {
        for (int i = 1; i <= 46; i++) {
            for (int j = i + 2; j <= 48; j++) {
                int count = i * (i + 1) + j * (j + 1);//一定要记得加括号
                for (int k = 1; k <= 49; k++) {//将其余的数相加
                    if (k != i && k != i + 1 && k != j && k != j + 1) {//判断k不是我们前面已经用来相乘的数
                        count += k; //将剩余的数加起来
                    }
                }
                if (count == 2015) {
                    System.out.println(i);//得到10  16
                }
            }
        }
    }
}
🔑解析:这道题也是经典的插入乘法的枚举问题。比较难处理的是如何进行相加和放乘号的位置。我们需要通过两个循环去模拟左右乘号的放入问题,外循环遍历左括号可能的位置,内循环遍历右括号可能的位置。因为乘号不可以相邻,所以左括号可能的位置是1的后面到46的后面,右括号每次起始的位置是i+2,最多可以到达48的后面。然后将第一个乘号的乘积加上第二个乘号的乘积得到count,然后遍历加上剩余的元素最后判断值是否是我们的2015。最后得到的输出有10和16,10是题目已经给过的答案,所以另外一个答案就16。

🍋3.蓝桥典型枚举问题总结和做题经验

以上我抽选的都是蓝桥杯较容易拿分的枚举填空题,这是我们拿分的关键,也是最容易拿分的题目。因为枚举只要你不着急,大胆去尝试和猜想,耐心的考虑到全部的情况,就一定可以算出答案。也不用去想着怎么去优化代码,只要能得到答案,就去尝试。当然得到答案后也一定要去验证一下,代码的细节也要把握好,否则很容易得到错误答案。最最主要的,还是要多加练习,包括以上的题目和以及视频资源我都为大家准备好了。

经验分享 程序员 职场和发展