2022蓝桥java b组省赛题解

1.星期计算

思路:可以用笔算也可以写代码

	public static void main(String[] args) {
		int res = 6;
		int cur = 1;
		for(int i=1;i<=22;i++){
			cur *= 20;
			cur %= 7;//需要取余否则会超int最大值
		}
		res = (res+cur)%7;
		if(res==0) res = 7;//如果res为0说明是星期天
		System.out.println(res);
    }

2.山 

思路:先枚举2022到2022222022然后判断是否为回文数,并且先单调不减后单调不增

判断回文可以有两种方法

	public static void main(String[] args) {
		int res = 0;
		for(int i=2022;i<=2022222022;i++){
			if(isSame2(String.valueOf(i).toCharArray())){//将int转化为char数组
				res++;
			}
		}
		System.out.println(res);
    }
	public static boolean isSame1(char[] s){
		int l = 0;
		int r = s.length-1;
		int mid = s.length/2;
		while(l<r){//判断左右是否相等不相等则不为回文数,左右端点向中心判断
			if(s[l]!=s[r]) return false;
			l++;
			r--;
		}
		l = 1;//将左边定义为第二个数
		while(l<=mid){//如果不递增则不为回文数
			if(s[l-1]>s[l]) return false;
			l++;
		}
		return true;
	}
	public static boolean isSame2(char[] s){  //中心扩展法
		int m = s.length/2;
		int sd = s.length%2==0? 0:1;  //判断奇偶位数
		int l = sd==1? m:m-1;	//定义左右指针位置    中间向两边扩展
		int r = m;
		//先判断1次,因为之后要判断左端点和左端点右边一个数是否为非递减
		if(s[l]==s[r]){	
			l--;
			r++;
		}
		else return false;
		while(l>=0){
			//如果左右相同并且左端点和左端点右边一个数为非递减,继续扩展
			if(s[l]==s[r]&&s[l+1]>=s[l]){
				l--;
				r++;
			}
			else{
				return false;
			}
		}
		return true;
	}

3.字符统计

 思路:枚举字符串每个字母出现次数

	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		String s = scan.next();
		int[] count = new int[26];//设一个数组记录26个字母出现次数
		int max = 0;//记录出现最多字母的个数
		for(char c:s.toCharArray()){
			count[c-'A']++;	 //遍历到1个字母时对应数组加1
			max = Math.max(max,count[c-'A']);
		}
		for(int i=0;i<26;i++){
			if(max==count[i]){
				System.out.print((char)('A'+i));//相同则输出大写字母
			}
		}
		scan.close();
    }

4.最少刷题数

 思路:先排序判断中位数关系,重点是对于当前学生全班刷题比他多的学生数不超过刷题比他少的学生数,开始是觉得超过中位数即可,不过后面想到若有很多个相同的中位数呢?

学生刷题数先可以分为三类,大于中位数,小于中位数,等于中位数

接着在统计 >中位数的个数 和 <中位数的个数,继续分三类,大于中位数的个数跟小于中位数个数的关系,例如 1 4 4 5 6,  1 4 5 6 7,  1 4 5 5 7,可以理解为中位数左边跟中位数相等的数多即需要超过中位数,反之则只需要等于中位数

public class Main {
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		int n = scan.nextInt();
		int[] gra = new int[n];
		int[] cou = new int[n];
		for(int i=0;i<n;i++){
			gra[i] = scan.nextInt();
			cou[i] = gra[i];
		}
		//gra为初始记录下来的数组   cou用来从小到大排序
		Arrays.sort(cou);
		//mid为中位数
		int mid = n/2;
		int res[] = new int[n];
		//记录比中位数小的个数和比中位数大的个数
		int pos = 0;
		int neg = 0;
		for(int num:gra){
			if(num>cou[mid]) pos++;
			if(num<cou[mid]) neg++;
		}
		for(int i=0;i<n;i++){
			//当前数比中位数大时肯定刷题比他多的学生数超过刷题比他少的学生数,跳过
			if(gra[i]>cou[mid]) continue;
			//当前数比中位数小时分类讨论
			if(gra[i]<cou[mid]){
				//例如 1 6 6 10 12  1 需要大于6才能达成条件
				if(pos>neg){
					res[i] = cou[mid]+1-gra[i];
				}
				//例如1 4 6 10 12  1,4需要大于6
				if(pos==neg){
					res[i] = cou[mid]+1-gra[i];
				}
				//例如1 4 6 6 6  1,4只需要等于6即可
				if(pos<neg){
					res[i] = cou[mid]-gra[i];
				}
			}
			//当前数比中位数小时分类讨论
			if(gra[i]==cou[mid]){
				//例如1 4 4 5 6  4需要超过4才可以达成条件
				if(pos>neg){
					res[i] = 1;
				}
			}
		}
		for(int i=0;i<n;i++){
			if(i==n-1){
				System.out.print(res[i]);
			}
			else{
				System.out.print(res[i]+" ");
			}
		}
		scan.close();
    }
}

5.求阶乘

思路:后缀0的个数一定是由*10得来,10的质因数为5*2,只需要判断5的个数和2的个数即可,2的个数一定是比5大的所以只用求5的个数,因为后缀0的个数一定是随着N的升高而提升所以具有单调性可以使用二分减少时间复杂度

相关题目:https://leetcode.cn/problems/factorial-trailing-zeroes/

import java.math.BigInteger;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        //在此输入您的代码...
        //因为数字超了long类型所以选择使用BigInteger类型
        BigInteger count = scan.nextBigInteger();
        BigInteger l = BigInteger.valueOf(0);
        BigInteger r = BigInteger.valueOf(1);
        BigInteger h = BigInteger.valueOf(10);
        for(int i=0;i<22;i++){
            r = r.multiply(h);
        }
        //二分
        while(!l.add(BigInteger.ONE).equals(r)){
            BigInteger m = (l.add(r)).divide(BigInteger.valueOf(2));
            BigInteger cur = tellZeros(m);
            if(cur.compareTo(count)>=0){
                r = m;
            }
            else {
                l = m;
            }
        }
        System.out.println(r);
        scan.close();
    }
    //递归得到后缀0的数量
    public static BigInteger tellZeros(BigInteger m){
        if(m.equals(BigInteger.ZERO)) return BigInteger.ZERO;
        return m.divide(BigInteger.valueOf(5)).add(tellZeros(m.divide(BigInteger.valueOf(5))));
    }
}

不过只过了90%不知道为什么。可恶

7.数组切分

 思路:动态规划,关键字划分,看看能不能把问题划分为子问题,发现数组为n的话,如果后面一段为有效划分即可加上前面一段的有效化分数,例如数组[1,2,3],需先求出[1]的有效化分数和[1,2]的有效化分数,如果[2,3]可以组成有效划分,即可加数组为[1]的有效化分数,如果[3]为有效化分即可加数组为[1,2]的有效划分

状态转移为f[i] = f[i] + f[j - 1]

相似题目 https://leetcode.cn/problems/check-if-there-is-a-valid-partition-for-the-array/

import java.util.PriorityQueue;
import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main {
    static int mod = (int)1e9+7;
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        //在此输入您的代码...
        int n = scan.nextInt();
        int[] nums = new int[n];
        for(int i=0;i<n;i++){
            nums[i] = scan.nextInt();
        }
        int[] dp = new int[n+1];//dp数组
        dp[0] = 1;//初始值为1
        for(int i=0;i<n;i++){
            for(int j=0;j<=i;j++){
                if(isConti(nums,i,j)){//判断nums[j]到nums[i]是否为一段
                    dp[i+1] += dp[j];//状态转移方程
                    dp[i+1] %= mod;
                }
            }
        }
        System.out.println(dp[n]);
        scan.close();
    }
    //开始想的是用一个优先队列判断
    public static boolean isConti(int[] nums,int i,int j){
        PriorityQueue<Integer> queue = new PriorityQueue<>();
        for(;j<=i;j++){
            queue.add(nums[j]);
        }
        int s = queue.poll();
        while (!queue.isEmpty()){
            int cur = queue.poll();
            //如果大的一个数减去小的不为1 即不是连续
            if(cur - s != 1) return false;
            s = cur;
        }
        return true;
    }
}

上面的方法判断是否为有效划分的时间较长通过70%,下面的用例都能通过

import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main {
    static int mod = (int)1e9+7;
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        //在此输入您的代码...
        int n = scan.nextInt();
        int[] nums = new int[n];
        for(int i=0;i<n;i++){
            nums[i] = scan.nextInt();
        }
        int[] dp = new int[n+1];//dp数组
        dp[0] = 1;//初始值为1
        for(int i=0;i<n;i++){
            int max = nums[i];
            int min = nums[i];
            //如果最大最小差值为i - j即为有效划分
            //例如 1 3 2 4 当 i = 3  j = 1为有效划分
            for(int j=i;j>=0;j--){
                max = Math.max(nums[j],max);
                min = Math.min(nums[j],min);
                if(max - min == i - j){//判断nums[j]到nums[i]是否为一段
                    dp[i+1] += dp[j];//状态转移方程
                    dp[i+1] %= mod;
                }
            }
        }
        System.out.println(dp[n]);
        scan.close();
    }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值