CSDN编程挑战赛第六期—题解(另附:最长上升子序列分析题解)

CSDN编程竞赛报名地址:https://edu.csdn.net/contest/detail/16
(请不要删掉此地址)

“路漫漫其修远兮,吾将上下而求索”

前言

笔者属于刚入门算法的萌新,也有参加天梯赛,蓝桥杯,acwing等这些算法比赛,成绩算一般,但是还在努力学习。
本次是笔者第一次参加CSDN的编程竞赛,因为是第一次参加,不太熟悉答题的流程,导致成绩并不是很高,但是笔者认为此次的四道题均不是很难,所以想借着创作活动来分享一下我的答题思路。

大赛简介

活动时间:9月8日-21日(竞赛时间截止9.18)
竞赛考试时间:9月18日 8:30-11:00(作答时间2小时)
获奖名单公布:9月23日,在本页面公布获奖名单链接
获奖用户信息收集:9月27日
奖品发放:9月30日后7个工作日内
竞赛:满分100分,4道编程题,编程题可使用Java、C、C++、C#、Python、JavaScript、lua、go等编程语言在这里插入图片描述
在这里插入图片描述CSDN编程竞赛是CSDN举办的编程比赛,一共四道编程题,难度适中,对萌新友好

参赛流程

因为是第一次参赛,比较匆忙,早上起床洗漱完就赶紧坐到电脑旁边,打开比赛网址进行答题,所以笔者建议大家早些起床,提前准备比赛的环境。
其次是比赛过程中要细心,笔者这次因为不细心导致出现了小的问题,也是比较后悔,但是后面重新去完成了错误的题,也算是对题目的再次熟悉。

参赛经历

提示:可介绍自己是如何准备参赛的,以及比赛过程中的分阶段时间安排和分工。
笔者参加的是第六期的比赛,因为四道编程题的难度是从简到难,所以按顺序从第一题开始做即可,如果遇到调试有问题,可以进入自测界面,通过设置输入样例,预期结果,即可分析实际输出的情况。
在这里插入图片描述

解题思路

1.题目名称:严查枪火

X国最近开始严管枪火。 像是“ak”,“m4a1”,“skr”。都是明令禁止的。 现在小Q查获了一批违禁物品其中部分是枪支。小Q想知道自己需要按照私藏枪火来关押多少人。 (只有以上三种枪被视为违法)

样例输入
5
ak
m4a1
skr
uzi
98k

样例输出
3

分析
本题应该算是送分题,只需要判断输入的是不是“ak”,“m4a1”,“skr”,然后统计即可,下面直接上代码。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        String str_0 = scan.nextLine().trim();
        int n = Integer.parseInt(str_0);
        ArrayList<String> vector = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            String str_1 = scan.nextLine().trim();
            vector.add(str_1);
        }
        scan.close();
        int result = solution(n, vector);
        System.out.println(result);
    }


    public static int solution(int n, ArrayList<String> vector) {
        int result = 0;
        for (int i = 0; i < n; i++) {
            switch (vector.get(i)) {
                case "ak":
                case "skr":
                case "m4a1":
                    result++;
                    break;
            }
        }
        return result;
    }
}

2.题目名称:鬼画符门

鬼画符门,每年都会统计自己宗门鬼画符消耗的数量,往年一直是大师兄管理, 但是这次鬼艺接手了, 你能帮鬼艺写一个程序统计每年消耗数量最多的鬼画符吗?

样例输入
5
red
red
green
green
blue

样例输出
red

分析
本题分析其实就是求出现次数最多的字符串,也很简单,直接上代码。

import java.util.*;

public class Main {
        public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        String str_0 = scan.nextLine().trim();
        int n = Integer.parseInt(str_0);
        ArrayList<String> vector = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            String str_1 = scan.nextLine().trim();
            vector.add(str_1);
        }
        scan.close();
        String result = solution(n, vector);
        System.out.println(result);
    }

    public static String solution(int n, ArrayList<String> vector) {
        String result = "";
        //创建一个HashMap存每种颜色的数量
        HashMap<String, Integer> maps = new HashMap<>();
        for (int i = 0; i < n; i++) {
            String str = vector.get(i);
            //判断maps里面有没有该颜色
            if (maps.containsValue(str)) {
            	//有的话就加1
                int num = maps.get(str);
                maps.put(str, num + 1);
            } else {
            	//没有的话就置1
                maps.put(str, 1);
            }
        }
        int max = -1;
        for (String str : maps.keySet()) {
            if (maps.get(str) > max) {
                max = maps.get(str);
                result = str;
            }
        }
        return result;
    }
}

3.题目名称:收件邮箱

已知字符串str,str表示邮箱的不标准格式。 其中”.”会被记录成”dot”,”@”记录成”at”。 写一个程序将str转化成可用的邮箱格式。(可用格式中字符串中除了开头结尾所有”dot”,都会被转换,”at”只会被转化一次,开头结尾的不转化)

样例输入
kevinwalkeratcsdndotcom

样例输出
kevinwalker@csdn.com

分析
本题因为笔者的不信息,导致出现问题,后面重新分析,完成了正确的结果。
本体主要条件为除了开头结尾所有”dot”,都会被转换,”at”只会被转化一次
所以我们只需要不让开头结尾的dot转换,并且转换一次at即可
因为字符串处理方法很多,笔者的思路是:
先将所有的dot转换为.,下面再判断首位是否为.,如果为.就把点再换成dot,然后再通过 reverse()方法逆序字符串,再照上面的思路继续转换
最后再通过replaceFirst()方法把at转换为@即可,下面上代码。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        String str_0 = scan.nextLine().trim();
        String str = str_0;
        scan.close();
        String result = solution(str);
        System.out.println(result);
    }

    public static String solution(String str) {
        String result = str;
        //把dot全部替换为.
        result = result.replaceAll("dot", ".");
        //判断首位是否为.
        if (result.indexOf(".") == 0) {
            result = result.replaceFirst(".", "dot");
        }
        //判断末尾是否为.
        //逆序字符串
        result = reverseStr(result);
        if (result.indexOf(".") == 0) {
            //替换逆序的首位
            result = result.replaceFirst(".", "tod");
        }
        //字符串再逆序回来
        result = reverseStr(result);
        //转换一次@
        result = result.replaceFirst("at", "@");
        return result;
    }

    public static String reverseStr(String str) {
        StringBuilder sb = new StringBuilder(str);
        return sb.reverse().toString();
    }
}

4.题目名称:最长递增的区间长度

给一个无序数组,求最长递增的区间长度。如:[5,2,3,8,1,9] 最长区间 2,3,8 长度为 3

样例输入
6
5 2 3 8 1 9

样例输出
3

分析
第一眼看到这个题,笔者想到是LIS(最长上升子序列),但是根据题目要求,只需要求最长连续递增的子序列长度,那么分析就很简单了,直接讲思路:
首先我们写一个List用来保存每个数字的连续子序列长度,然后一次判断前一位是否小于自己,小于则+1,大于则重置为 1。
直接上代码:

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        String str_0 = scan.nextLine().trim();
        int n = Integer.parseInt(str_0);
        String str_1 = scan.nextLine();
        String[] line_list_1 = str_1.trim().split(" ");
        ArrayList<Integer> arr = new ArrayList<>();
        for (int i = 0; i < line_list_1.length; i++) {
            arr.add(Integer.parseInt(line_list_1[i]));
        }
        scan.close();
        int result = solution(n, arr);
        System.out.println(result);
    }

    public static int solution(int n, ArrayList<Integer> arr) {
        int result = 0;
        List<Integer> list = new ArrayList<>();
        list.add(1);
        for (int i = 1; i < n; i++) {
            if (arr.get(i) > arr.get(i - 1)) {
                list.add(list.get(i - 1) + 1);
            } else {
                list.add(1);
            }
        }
        result = Collections.max(list);
        return result;
    }
}

5.笔者补充的题目:最长上升子序列

给一个无序数组,求最长递增的区间长度。如:[5,2,3,8,1,9] 最长区间 2,3,8,9 长度为 4

样例输入
6
5 2 3 8 1 9

样例输出
4

分析
这个题相较于本次比赛的第四题是有些相似的,但是去掉了连续的条件,所以我们要用动态规划来分析。
首先列出dp数组的定义:a[i]表示arr[i]为结尾的最长子序列长度
状态转移方程:a[i] = a[j] + 1 条件为:( 0 < j < i , arr[j] < arr[i] )
众所周知,动态规划就是空间换时间,所以我们要通过建立数组a[]来保存状态
a[]的索引即是所给数组每一位的情况下的最长子序列长度。
每次给a[i]初值置1,然后一次与i前面的j位进行比较,然后取符合arr[j] < arr[i]的情况下的max(a[j]+1,a[i])

举个例子:
假设当前数组为[5,2,3,8,1,9]
第一个数 5,最长上升子序列为[5],长度为1
第二个数 2,在2前面未找到比2小的数字,所以最长上升子序列为[2],长度为1
第三个数 3,在3前面找到比3小的数字2,所以max(1,1+1),所以最长上升子序列为[2,3],长度为2(1+1是指上一项2的最长上子序列长度)
第四个数 8,再8前面找到了3个比8小的数字,分别用他们的长度+1与8的初始长度比较(长度初始值为1),所以最长上升子序列为[2,3,8],长度为3
第五个数 1,在1前面未找到比1小的数字,所以最长上升子序列为[1],长度为1
第六个数 9,再9前面找到了5个比9小的数字,分别用他们的长度+1与9的初始长度比较(长度初始值为1),所以最长上升子序列为[2,3,8,9],长度为4

如果你有大概的想法,但是脑子里并没有大概的代码,直接看下面的代码就可以明白了:

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        String str_0 = scan.nextLine().trim();
        int n = Integer.parseInt(str_0);
        String str_1 = scan.nextLine();
        String[] line_list_1 = str_1.trim().split(" ");
        ArrayList<Integer> arr = new ArrayList<>();
        for (int i = 0; i < line_list_1.length; i++) {
            arr.add(Integer.parseInt(line_list_1[i]));
        }
        scan.close();
        int result = solution(arr);
        System.out.println(result);
    }

    public static int solution(ArrayList<Integer> arr) {
        int result = 0;
        if(arr.size() == 0) return 0;
        int[] a = new int[arr.size()];
        int res = 0;
        for(int i = 0; i < arr.size(); i++){
            a[i] = 1;
            for(int j = 0; j < i; j++){
                if(arr.get(j) < arr.get(i)){
                    a[i] = Math.max(a[i], a[j]+1);
                }
            }
            result = Math.max(result, a[i]);
        }
        return result;
    }
}

经验心得

提示:可总结自己参赛的经验心得,给大家一些建议参考。
本次参加完比赛的最大心得就是一定要好好准备,不要像笔者一样粗心大意,导致犯了很多不该犯的错误
总结下来就是:本次比赛的题难度都不大,如果你是跟笔者一样刚入门算法的小白的话,可以当作锻炼的过程来参加比赛,会对你有很大的帮助,而且最好是可以在参加完比赛后,将错的地方重新写一遍,把粗心的地方细心总结一下,如果可以温故知新那就是最好,这也是笔者在最后面补充了一道最长上升子序列的问题一样。

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值