蓝桥杯刷题日记——美丽的区间

前言

哈喽大家好,我是浅夜,一名正在备战14届蓝桥杯的java小菜鸡,想跟大家分享一些我在备赛刷题过程中遇到的有趣的题目或者做题模板,同时也能让我自己记录和巩固学到的知识点,也算是记录自己的成长吧。哈哈哈有点长远哈,其实之前受到蓝桥云课代练学长也是咱们CSDN大佬执梗的启发,老早就想写博客了,但是实在太懒了哈哈,所以时至今日才来写我的第一篇博客,此时有一种相见恨晚的心情,虽然可能有点夸张,但的确是有些小激动的哈哈。

好的,废话不多说哈,接下来我们来看题目——美丽的区间

题目

题目描述

给定一个长度为 n 的序列 1,2,⋯,a1,a2,⋯,an 和一个常数 S

对于一个连续区间如果它的区间和大于或等于 S,则称它为美丽的区间。

对于一个美丽的区间,如果其区间长度越短,它就越美丽。

请你从序列中找出最美丽的区间。

输入描述

第一行包含两个整数 n,S,其含义如题所述。

接下来一行包含 n 个整数,分别表示 1,2,⋯,a1,a2,⋯,an

10≤N≤105,1×≤1e4 1×ai≤1e4,1≤≤1081≤S≤108。

输出描述

输出共一行,包含一个整数,表示最美丽的区间的长度。

若不存在任何美丽的区间,则输出 00。

输入输出样例
示例 1
输入
5 6
1 2 3 4 5
输出
2
运行限制
  • 最大运行时间:1s

  • 最大运行内存: 128M

做题思路

这道题的描述还是比较容易理解的,它输入一段序列,要我们求出这段序列中的一段最短连续序列,这个连续序列要满足它的和要大于等于给定值S。

如果我们用二分来做,那我们如何构思?

首先我们只需要想,如何将二分二段性来结合到这道题上,看下面这张图,假设输入的序列中有区间[a,b],而且这段区间的和恰好等于S,因为序列中都是正数,那么是不是[a,b+1],[a,b+2]...[a,n]都满足美丽区间的定义,也就是是说:如果能找到一个长度为x的美丽区间,那么长度大于x的区间也是美丽区间,而前面这一段就不够x的长度,便是我们要舍去的,这样就满足了二分的二段性。题目要求的是最美丽(最短)的区间,那[a,b]正是我们要求的最美丽的区间。

蓝桥杯刷题日记——美丽的区间_第1张图片

我们说二分是一看就会,一写就废,它好像说起来很简单,那我们到底怎么去实现呢?

我们需要先枚举二分的左边界,就是上面说的a,然后再以a为起点往后累加求和,到第一个满足和大于等于S的序列值b时,[a,b]便是最美丽的区间。我们要注意,此时最美丽的区间还并不一定是题目最终答案,这只是以a为左边界情形下的最美丽的区间,还需要从我们枚举的所有左边界求出的所有“最美丽区间”中求最小值,得到的才是最终题目要求的答案!

更多实现的细节,我会在接下来的代码中有更祥细的注释,还不太理解的话可以看注释奥~

import java.io.*;

public class 美丽的区间 {
    //因为最大运行时间1s的限制,所以我们要用到快读BufferedReader
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
    static int N = 100010;//后面要开长度为N的数组,为防止数组越界,N开大一点
    //这里我们开一个数组g,专门用来存储某一段区间的和
    static int[] a = new int[N], g = new int[N];

    public static void main(String[] args) throws IOException {
        String[] s = br.readLine().split(" ");
        int n = Integer.parseInt(s[0]);
        int t = Integer.parseInt(s[1]);//这里t是题目提到的S
        int ans = N;
        s = br.readLine().split(" ");
        for (int i = 1; i <= n; i++) {
            a[i] = Integer.parseInt(s[i - 1]);
            //前缀和函数 用来存储左边界到第i项的和
            g[i] = a[i] + g[i - 1];
        }

        //枚举 i 即二分的左边界 然后将以左边界为起始的前缀和组成的数组中来通过二分查找目标值t
        //时间复杂度 O(nlogn)
        for (int i = 1; i <= n; i++) {
            //二分的复杂度为logn
            int l = i, r = n;
            while (l < r) {
                int mid = l + r >> 1;
                //通过二分不断查找第一个满足大于等于t的序列下标
                if (g[mid] - g[i - 1] >= t) r = mid;
                else l = mid + 1;
            }
            /*
                此时我们只需要将二分得到的最终结果g[r]减去前i-项的和便得到了满足大于给定
            值的和 。因为我们枚举了左边界,题目要求我们找到最短的区间,所以我们还
            应该找出结果当中最小的值,才是我们最终要求的答案
            */
            if (g[r] - g[i - 1] >= t) ans = Math.min(ans, r - i + 1);
        }
        //按照题目要求判断,当求和求到序列结尾还是小于S时,就输出0
        out.println(ans == N ? 0 : ans);
        out.flush();//刷新此输出流并强制写出所有缓冲的输出字节
    }
}

总结

要做出这道题,首先我们要对二分的二段性敏感一点(我认为二分做题最重要的一点),像我刚开始做这道题的时候也没能想到要对序列的和来进行二分,对和二分的话那个前缀和的数组也是需要好好理解理解,还是二分题刷的太少了吧哈哈哈,人家大佬都说万物皆可二分,我还没体会到,看来还得再来个几十道哈哈哈哈。其次呢最近接触的几道题都需要快读来进行输入输出,而我对这个不那么熟练,就出好多错,很艰难的过程,希望大家也要扩大知识面,不要像我一样知识到用处~~~方恨少呐~

我自己本身也在学习初级阶段,对题目理解有问题的地方还请各位大佬海涵,如能提醒纠正,将不胜感激!

文短情长,美丽的区间这道题就跟大家分享到这里啦!值此新年之际,并纪念我的第一篇博客完成,给大家放个烟花~biu~~boom~~祝大家新的一年题题AC呀~

我们下一篇不见不散......

你可能感兴趣的:(备赛必刷题,蓝桥杯,java,算法)