无论结果多么差,请别放弃,收起你的沮丧,重头再来!!!(算法详解)

1、前言

        临近比赛,我决定找个模拟测试检验一下自己的水平,结果,被虐的体无完肤,完全下不了手,一点思路都没有,赛后,我查看别人大佬的代码,发现我想了半天的题别人4-5行代码就搞定了,说实话,当时自己心里还是挺难受的。觉得自己辛辛苦苦学了近一个月的算法,到头来,就这!。。。。。。。。我不甘心啊,但是现实摆在面前,我不得不接受。不过,虽然很不甘心,尽管连自己都觉得自己是一个废物,但,还没到放弃的时候,如果放弃,那么这一个月就真的毫无意义了,当你颓废的时候,想想曾经努力的‘你‘,昨天的‘你’努力的成果是让今天的你去挥霍的吗?既然今天失败了,那就拼命的去努力,向明天的你证明,‘我’,不是废物!!!。今天我在书中看到这样一段话:井底之蛙,不知海之宽广,却晓天之蔚蓝;成功的路上一定不平坦,即便不能够到达终点,但至少,我欣赏过沿途的风景,不是吗?

2、来看看👀虐我的都是些什么题吧!

2.1、 b 小明的作业


题目链接:b 小明的作业

        个人错误原因: 当前看到这题,立即就想着用通过改变字符串的长度递归去匹配字符串,但是写到后面,我发现我无法确定一个Error的长度,因为Error是连续的‘aw’||‘wa’,只要是连续的,都表示一个Erro,这里我就犯难了,不知道字符串的长度匹配是很难实现的,当时我的想法是使用while循环来判断一个连续的‘wa’||‘aw’,直到不再连续,结束循环,然后截取这部分的字符串继续执行下一次的判断,这样写貌似可行,但代码特别的冗余,且需要定义特别多的辅助变量,越写到后面,我就越懵,最后,我直接看不懂自己的代码了,无奈只好放弃😣。

        题目分析: 这题主要考点就是对字符串的理解。任意给定一个字符串,判断Warning(警告)和Error(错误)的数量,根据题意分析,Error的优先级是要高于Warning的,也就是说,当出现类似‘wawawaaw’这种字符串的时候,先判断连续awaw||wawa(Error),然后再判断单个的wa||aw(Warning),所以,‘wawawaaw’就表示一个Error和一个Warning,但是呢,对于一个连续的不确定的字符串我们用暴力穷举很难去查找,所以呢,这个时候我们就需要换一个思路,比如,利用正则表达式去匹配,String类有一个方法为replaceAll,其主要作用是替换字符串中的部分字符,该方法的重载就是利用正则表达式去匹配并替换字符串,利用这个方法,我们就能很轻松的解决这道题了。

String a="iawaswapwauawhawdwafwanbiopwanivgbikvblvbwawawawvolyuvgbololvolgbyolgyowagbolgawgboplwawaolgyolwaogblwaygbowawagwabwayawopwawagyowabwaowapjwapcfrtuywawacvujwawawaufttyfuftywawawatifgugbgbyguwawawawayugbigwwwytigwygwgbwyoawawgoghwaogwborgrewabouyhwabyuhowabhnwawauygbawyawuwaoawfcawaaaahwaywauwagwawefwaafmbawklawjiawihnwanhawawawawijwajiofjeriofgjrefjhwaewarwaowagwahwauwaiwarwaiwaqwarwahwaqwawwaowapfweofbwewafwahwaiwaewawwawawawawafwawawawaeiufwepfhnewfwahwajwatwafowawajtokshwawafwaiwahwafwahmgoewawawawafkfjkewnwawafiewhfwawawafjkernhawkrenwawawawafujnrheiowanwakawawawawwanoifewajrwaoawawfweojnwawawawawawawafjkwenawawferkwmpwawawawaforeijawawferhfiueorghwuwafguwegfwaghrwiufgwahweofgowaidwiweaiwwawieyiwe";
       //匹配连续出现2次或2次以上的aw或wa,将其替换为‘0’并将结果返回给原字符串
        a=a.replaceAll("(aw){2,}|(wa){2,}","0");
        //匹配单个的aw或wa,将其替换为‘1’并将结果返回给原字符串
        a=a.replaceAll("wa|aw","1");
        int b=0;
        int c=0;
        //枚举一下‘0’和‘1’的个数,即可得到结果
        for (int i=0;i<a.length();i++){
            if (a.charAt(i)=='0'){
                b++;
            }else if (a.charAt(i)=='1'){
                c++;
            }
        }
        System.out.println(c);
        System.out.println(b);

2.2、 c 斐波那契


题目链接:c 斐波那契

        个人错误原因: 刚开始拿到这题,我的想法是直接找出所有分母的最小公倍数,然后去除以每一个数的分母得到的就是分子了,但是没想到数据太大了直接超出了long的范围,于是我改换成BigDecimal进行操作,但是这个类我还不是特别熟,只记得四则运算的方法,我找到了他们的最小公倍数,并得到了每一个数的分子,好像快做完了,结果,化简把我给难住了,因为我不知道BigDecimal有求公约数的方法,气死我了,嗷嗷嗷嗷嗷!!😠😠😠

        题目分析: 求斐波那契就不说了,相信大家都会,关于这题,其实是通过斐波那契变化而来的一个类似求分数通分的题,它本身并不难,只是细节部分需要处理好,废话不多说,直接上代码。

方式1:

public static void main(String[] args) {
        int[] F=new int[14];
        F[0]=1;
        F[1]=1;
        for (int i = 2; i < F.length; i++) {
            F[i]=F[i-1]+F[i-2];
        }
        int[] arr=new int[13];
        for (int i = 0; i < arr.length; i++) {
            arr[i]=F[i]*F[i+1];
            //System.out.println(arr[i]);
        }
        String s = Arrays.toString(arr);
        System.out.println(s);
        BigInteger fm=new BigInteger("1");
        BigInteger fz=new BigInteger("1");
        BigInteger gys=new BigInteger("0");
        for (int i = 1; i < arr.length; i++) {
            //前一个数的的分子,因为当前数较大,所以需要通分,分子和分母都需要乘以分母
            //而又因为,前一个数和当前数进行通分,当前数的分子必为1,所以,对于当前数的分子,我们可以直接用前一个数的分母表示
            //例如:3/2 和 1/6
            //对其通分的话就是 3*6/2*6 + 1*2/6*2  => 3*6/2*6  2/6*2
            fz=fz.multiply(new BigInteger(arr[i]+""));
            fz=fz.add(fm);
            fm=fm.multiply(new BigInteger(arr[i]+""));
            //System.out.println("分子:"+fz);
            //System.out.println("分母:"+fm);
        }
        //取分子与分母的公约数
        gys=fz.gcd(fm);
        //化简
        BigInteger zuijianfz=fz.divide(gys);
        BigInteger zuijianfm=fm.divide(gys);
        System.out.println(zuijianfz+"/"+zuijianfm);
    }

简化一下:方式2

 public static void main(String[] args) {
 		//斐波那契数组
        long[] arr = new long[14];
        arr[0] = 1;
        arr[1] = 1;
        //分子
        long upper = 1;
        //分母
        long downer = 1;
        for (int i = 2; i < 14; i++) {
        	//当前的斐波那契数
            arr[i] = arr[i - 1] + arr[i - 2];
            //当前项对应的分子:
            //(arr[i] * arr[i - 1]):当前项对应的分母
            upper = (arr[i] * arr[i - 1]) * upper + downer*1;
            //分母:因为每次循环计算分子需要的是上一项的分母,所以放在下面
            downer *= (arr[i] * arr[i - 1]);
            long gcd = gcd(upper, downer);
            upper /= gcd;
            downer /= gcd;
        }
 
        System.out.println(upper + "/" + downer);
    }
 
    //最大公约数:辗转法
    public static long gcd(long a, long b) {
        return b == 0 ? a : gcd(b, a % b);
    }

2.3、d 数列重组


题目链接:数列重组
        个人错误原因: 额,这题。。。emmm,反正就是不会啦,完全没头绪,拿到就懵了,就这,想笑就笑吧(╮(╯▽╰)╭)。

        题目分析: 暂时还不会,不过我估计应该是DFS类型的题,再给我点时间,等我学成归来,再来补这篇文章。

借鉴一下大佬的代码:

static boolean[] st = new boolean[11];
    static int A[] =new int[]{0,2,5,3,6,3,6,7,3,7,8};
    static int temp[] = new int[11];
    static Set<String > set = new LinkedHashSet<>(); //记录无重复全排列。
    public static void main(String[] args) {
        //去重全排列问题。
        // 2 5 3 6 3 6 7 3 7 8
        dfs(1);
        int ans = 0;
//        System.out.println(set.size());
 
        for(String s:set){
            boolean flag = false;
            char[] c = s.toCharArray();
            for(int k1 = 2;k1<=8;k1++){   //枚举2个分段点。
                for(int k2= k1+1;k2<=9;k2++){
                        if(check(c,k1,k2)){
                            flag = true;
                            break;
                        }
                }
                if(flag==true){  //不用枚举了
                    ans++;
                    break;
                }
            }
        }
        System.out.println(ans);
    }
 
    static void dfs(int n){
        if(n==11) {
            add(temp);
            return;
        }
        for(int i = 1;i<=10;i++){
            if(st[i]==false) {
                temp[n] = A[i];
                st[i] = true;
                dfs(n + 1);
                st[i] = false;
            }
        }
    }
 
    static void add(int[] ans){
        StringBuilder s = new StringBuilder();
        s.append("0");
        for(int i = 1;i<=10;i++){
            s.append(ans[i]);
        }
        set.add(s.toString());
    }
 
    static boolean check(char c[],int k1,int k2){  // 判断三段是否有序。 //升序 或者 逆序。
        boolean flag = true;
        int re = 0;
 
        for(int i = 1;i<=k1;i++){
            if(i+1<=k1 && c[i+1]>c[i]) {
                if(re==0) re=1;
                if(re==-1) {
                    flag = false;
                    break;
                }
            }
            if(i+1<=k1 && c[i+1]<c[i]) {
                if(re==0) re=-1;
                if(re==1) {
                    flag = false;
                    break;
                }
            }
        }
        if(flag==false) return false;
        re = 0;
 
        for(int i = k1+1;i<=k2;i++){
            if(i+1<=k2 && c[i+1]>c[i]) {
                if(re==0) re=1;
                if(re==-1) {
                    flag = false;
                    break;
                }
            }
            if(i+1<=k2 && c[i+1]<c[i]) {
                if(re==0) re=-1;
                if(re==1) {
                    flag = false;
                    break;
                }
            }
        }
        if(flag==false) return false;
        re = 0;
 
        for(int i = k2+1;i<=10;i++){
            if(i+1<=10 && c[i+1]>c[i]) {
                if(re==0) re=1;
                if(re==-1) {
                    flag = false;
                    break;
                }
            }
            if(i+1<=10 && c[i+1]<c[i]) {
                if(re==0) re=-1;
                if(re==1) {
                    flag = false;
                    break;
                }
            }
        }
        return flag;
    }

2.4、e 三角形的个数


题目链接:三角形的个数
        个人错误原因: 每一个三角形的个数数错了,导致总结的规律出错(ps:写题写错也就算了,数个数都数不明白[○・`Д´・ ○])

        题目分析: 根据别人大佬总结的规律

  • 偶:n*(n+2)(2n+1)/8
  • 奇:n*(n+2)(2n+1)-1)/8

        直接套公式就完了,下面上代码:

public static void main(String[] args) {
        //偶:n*(n+2)*(2*n+1)/8
        //奇:n*(n+2)*(2*n+1)-1)/8
        BigInteger n=new BigInteger("20210411");
        BigInteger m=new BigInteger("2");
        BigInteger a=new BigInteger("1");
        BigInteger b=new BigInteger("8");
        BigInteger q=new BigInteger("1000000007");
        BigInteger geshu=(n.multiply(n.add(m)).multiply((m).multiply(n.add(a)).subtract(a)).divide(b)).mod(q);
        System.out.println(geshu);
    }

3、结语


         为避免篇幅过长,先更新一半,后5题等将会在经期更新!!!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值