2019校招真题--网易-牛客

网易刷题


前言:2019校招真题,java编写,代码尽可能带注释,部分题目附上解题思路。如有错误,请指出,谢谢。

感悟:刷题重在思路以及巩固知识点,而不是刷题进度。

重点:TreeMap、递归、滑窗

1、网易-牛牛找工作

题目描述

为了找到自己满意的工作,牛牛收集了每种工作的难度和报酬。
牛牛选工作的标准是在难度不超过自身能力值的情况下,牛牛选择报酬最高的工作。
在牛牛选定了自己的工作后,牛牛的小伙伴们来找牛牛帮忙选工作,牛牛依然使用自己的标准来帮助小伙伴们。
牛牛的小伙伴太多了,于是他只好把这个任务交给了你。

输入描述:

每个输入包含一个测试用例。
每个测试用例的第一行包含两个正整数,分别表示工作的数量N(N<=100000)和小伙伴的数量M(M<=100000)。
接下来的N行每行包含两个正整数,分别表示该项工作的难度Di(Di<=1000000000)和报酬Pi(Pi<=1000000000)。
接下来的一行包含M个正整数,分别表示M个小伙伴的能力值Ai(Ai<=1000000000)。
保证不存在两项工作的报酬相同。

输出描述:

对于每个小伙伴,在单独的一行输出一个正整数表示他能得到的最高报酬。
一个工作可以被多个人选择。

示例1

输入
3 3 
1 100 
10 1000 
1000000000 1001 
9 10 1000000000
输出
100 
1000 
1001

1.1 借鉴其他代码,去复习TreeMap和HashMap区别,会对键值对排序

import java.util.Map;
import java.util.Scanner;
import java.util.TreeMap;

// 当前不需要排除N,M,D,P,A异常值仍能通过
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        //输入工作数量和伙伴数量
        int N = sc.nextInt();// 工作数量
        int M = sc.nextInt();// 小伙伴数量
        // 排除异常值
        //if(N <0 || N > 100000 || M < 0 || M > 100000)
            //return;
        // D 工作难度, P 为报酬, A 为小伙伴的能力值
        int[] D = new int[N], P = new int[N], A = new int[M];
        // 如果工作难度相同,新工作报酬更高就更新
        Map<Integer, Integer> map = new TreeMap<>();
        for(int i = 0; i < N; i++) {
            // 输入工作难度和报酬数组
            D[i] = sc.nextInt();
            P[i] = sc.nextInt();
            // 排除异常值
            //if(D[i] <0 || D[i] > 1000000000 || P[i] < 0 || P[i] > 1000000000)
                //return;
            // 这里保证不存在两项工作的报酬相同,怎么实现
            // 若两项工作的报酬相同,肯定选择难度小的,这就没意思了?
            //if(map.containsValue(P[i]) )
                //return;
            if (!map.containsKey(D[i])) {
                map.put(D[i], P[i]);
            } else {
                // 输入存在工作难度相同的情况
                if (P[i] > map.get(D[i])) {
                    map.put(D[i], P[i]); //只有工作难度相同,报酬更高才更新
                }
            }
        }
        // 输入M个伙伴的工作能力
        for(int i = 0; i < M ;i++) {
            A[i] = sc.nextInt();
            // 排除异常值
            //if(A[i] <0 || A[i] > 1000000000 )
                //return;
            if (!map.containsKey(A[i])) {
                map.put(A[i], 0); // 若map中没有对应的工作能力,那么就添加,报酬暂时置为0
            }
        }
        // 遍历map中能力报酬条目,报酬为0的那栏更新
        int max = Integer.MIN_VALUE;
        for(Map.Entry<Integer, Integer> entry : map.entrySet()){
            max = Math.max(max, entry.getValue());
            if(max != entry.getValue() ){
                map.put(entry.getKey(), max);
            }
        }
        // 遍历小伙伴数组
        for(int i = 0; i < M ; i++){
            System.out.println(map.get(A[i]));
        }
    }
}

1.2 心得

1.遍历:o(M*N),超时
2、拆分多层数组为单层数组
2.排序+map:
本题中,工作可以多次选择,只需要考虑工作,建立一个map,存储工作能力-报酬映射关系,把小伙伴的能力和报酬也存储进去,报酬初始化为0;从小到大依次更新最大报酬,有动态规划和马尔可夫过程的思想存在,当前最大报酬取决于当前能力与前一个能力对应的最大报酬。

1、将所有的能力值和薪酬一一对应填入map中,如果当前能力值有多个对应薪酬,只添加最高的那个。
2、将同学的能力值也一一加入map中,如果原先已经有就直接跳过,如果没有就把value设为0。也同时记录下当前能力值,用于输出结果。
3、遍历一遍map,由于map已经排过序,能力越大,对应的薪酬应该也越大,所以,将map中后面val小于前面val的值全部更新,使得map的val对应在当前能力值下所能获得最高的薪酬类似于动态规划。
4、最后直接输出就可以了,直接对应存下的能力数组直接进行输出

2、网易-被3整除

题目描述

小Q得到一个神奇的数列: 1, 12, 123,...12345678910,1234567891011...。
并且小Q对于能否被3整除这个性质很感兴趣。
小Q现在希望你能帮他计算一下从数列的第l个到第r个(包含端点)有多少个数可以被3整除。 

输入描述:

输入包括两个整数l和r(1 <= l <= r <= 1e9), 表示要求解的区间两端。
输出描述:
输出一个整数, 表示区间内能被3整除的数字个数。

示例1

输入
2 5
输出
3
说明
12, 123, 1234, 12345...
其中12, 123, 12345能被3整除。

2.1 借鉴其他代码,对于大量数据遍历不可取,甚至二重循环也不行

import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            int l = sc.nextInt();
            int r = sc.nextInt();
            int cnt = calc(r) - calc(l - 1 );
            System.out.println(cnt);
        }
    }
    // 统计从第1至第n能被3整除的个数
    private static int calc(int n){
        return n * 2/ 3;
    }
}

2.2 错误心得,代码稍微改动下,不做sc.hasNext()直接出错,以后最好数据先判断再输入

import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        //while (sc.hasNext()) {
            int l = sc.nextInt();
            int r = sc.nextInt();
            int cnt = calc(r) - calc(l - 1 );
            System.out.println(cnt);
        //}
    }
    // 统计从第1至第n能被3整除的个数
    private static int calc(int n){
        return n * 2/ 3;
    }
}

错误

3、网易-安置路灯

题目描述

小Q正在给一条长度为n的道路设计路灯安置方案。
为了让问题更简单,小Q把道路视为n个方格,需要照亮的地方用'.'表示, 不需要照亮的障碍物格子用'X'表示。
小Q现在要在道路上设置一些路灯, 对于安置在pos位置的路灯, 这盏路灯可以照亮pos - 1, pos, pos + 1这三个位置。
小Q希望能安置尽量少的路灯照亮所有'.'区域, 希望你能帮他计算一下最少需要多少盏路灯。 

输入描述:

输入的第一行包含一个正整数t(1 <= t <= 1000), 表示测试用例数
接下来每两行一个测试数据, 第一行一个正整数n(1 <= n <= 1000),表示道路的长度。
第二行一个字符串s表示道路的构造,只包含'.''X'

输出描述:

对于每个测试用例, 输出一个正整数表示最少需要多少盏路灯。

示例1

输入
2
3
.X.
11
...XX....XX
输出
1
3

3.1 仔细分析题目,不要犯常识性错误,例如路灯紧密安装,不要盲目做题

import java.util.Scanner;

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();// t表示测试用例数
        // 分析,关键找出路灯安装位置
        // 若pos位置字符为. 那么直接在pos+1位置安装路灯,而pos+2位置肯定能被照亮
        // 跳到pos+3位置继续判断
        // 误区,路灯没必要紧密安装,可以容忍照亮不需要照明位置,但需要照明位置一定要照亮
        // 输入道路长度以及道路构造
        for(int i = 0; i < t; i++){
            int n = sc.nextInt();
            String road = sc.next();
            //System.out.println(road);
            int cnt = 0; // 路灯数量
            int pos = 0; // 辅助定位
            while(pos < road.length() ){
                if(road.charAt(pos) == '.'){
                    cnt++;
                    pos += 3;
                }
                else if(road.charAt(pos) == 'X')
                    pos++;
            }
            System.out.println(cnt);
        }
    }
}

3.2 错误心得

1、开始就分析特殊边界情况,字符串匹配、正则表达式以及切分,容易陷入越分析越复杂困境。
2、非常多的输入情况,可以反复执行输入、处理、输出,不需要一次性读取存入多层数组,再处理。

4、网易-迷路的牛牛

题目描述

牛牛去犇犇老师家补课,出门的时候面向北方,但是现在他迷路了。
虽然他手里有一张地图,但是他需要知道自己面向哪个方向,请你帮帮他。

输入描述:

每个输入包含一个测试用例。
每个测试用例的第一行包含一个正整数,表示转方向的次数N(N<=1000)。
接下来的一行包含一个长度为N的字符串,由L和R组成,L表示向左转,R表示向右转。

输出描述:

输出牛牛最后面向的方向,N表示北,S表示南,E表示东,W表示西。

示例1

输入
3
LRR
输出
E

4.1 初始化方向数组

import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        //
        String[] dirs = {"W", "N", "E", "S"}; // 定义方向数组
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext() ){
            int cnt = sc.nextInt();
            String dir = sc.next();
            int pos = 1; // 初始方向设为北
            for(int i = 0; i < cnt; i++){
                if(dir.charAt(i) == 'L'){
                    pos = Math.floorMod((pos - 1), 4); // 每左转一次,dirs的pos向左移
                    continue;
                }
                if(dir.charAt(i) == 'R'){
                    pos = Math.floorMod((pos + 1), 4);// 每右转一次,dirs的pos向右移
                }
            }
            System.out.println(dirs[pos] );
        }
    }
}

4.2 心得,分清转向规律

5、网易-数对

题目描述

 牛牛以前在老师那里得到了一个正整数数对(x, y), 牛牛忘记他们具体是多少了。
但是牛牛记得老师告诉过他x和y均不大于n, 并且x除以y的余数大于等于k。

牛牛希望你能帮他计算一共有多少个可能的数对。 

输入描述:

输入包括两个正整数n,k(1 <= n <= 10^5, 0 <= k <= n - 1)

输出描述:

对于每个测试用例, 输出一个正整数表示可能的数对数量。

示例1

输入
5 2
LRR
输出
7
说明
满足条件的数对有(2,3),(2,4),(2,5),(3,4),(3,5),(4,5),(5,3)

5.1 要想余数能>=k,那么被除数至少要为k+1才有可能,而且肯定要利用数学关系,否则遍历绝对满足不了时间要求

参考题解
若直接暴力枚举时间复杂度为O(n^2),不能接受
分析,对于除数y,肯定要大于等于k,不然x%y肯定小于等于k,再来看被除数x
当对于一个被除数确定,此时遍历一遍x。

现在的问题是对于某个特定的y如何计算满足条件的个数,由于x属于[1,n]区间,我们在将其划分为若干个小区间如下:
[1, 2, …, y]
[y+1, y+2, …, 2y]
[2y+1, 2y+2, …, 3y]

[ty+1, ty+2, …, n]
其***有t=n/y个小区间,在每个区间内有y-k个元素其x%y大于等于k。
对于最后一个区间,其大于k的元素数量为y%k-k+1个,当然这个数字可能小于0,所以要进行一个比较

import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext() ){
            int n = sc.nextInt(); // x,y均不大于n,即1 <= x,y <= n,且x % y >= k;
            int k = sc.nextInt(); // 0 <= k <= n-1, 注意这里余数为0的情况,任何相除余数都不小于0
            Long cnt = 0L;
            for(int y = k+1; y <= n; y++){
                int res = 0;
                res = (int)(n / y * (y - k) ); //统计能整除后面余数>=k部分
                if((n % y) >= k){ // 统计最后一行
                    if( k != 0){
                        res += (n % y) - k + 1;
                    }
                    else{
                        res += (n % y);
                    }
                }
                cnt += res;
            }
            System.out.println(cnt);
        }
    }
}

5.2 认真分析现状

6、网易-矩形重叠

题目描述

平面内有n个矩形, 第i个矩形的左下角坐标为(x1[i], y1[i]), 右上角坐标为(x2[i], y2[i])。
如果两个或者多个矩形有公共区域则认为它们是相互重叠的(不考虑边界和角落)。
请你计算出平面内重叠矩形数量最多的地方,有多少个矩形相互重叠。 

输入描述:

输入包括五行。
第一行包括一个整数n(2 <= n <= 50), 表示矩形的个数。
第二行包括n个整数x1[i](-10^9 <= x1[i] <= 10^9),表示左下角的横坐标。
第三行包括n个整数y1[i](-10^9 <= y1[i] <= 10^9),表示左下角的纵坐标。
第四行包括n个整数x2[i](-10^9 <= x2[i] <= 10^9),表示右上角的横坐标。
第五行包括n个整数y2[i](-10^9 <= y2[i] <= 10^9),表示右上角的纵坐标。

输出描述:

输出一个正整数, 表示最多的地方有多少个矩形相互重叠,如果矩形都不互相重叠,输出1。

示例1

输入
2
0 90
0 90
100 200
100 200

输出
2

6.1 若多个矩形重叠,那么一定存在点在绝大多数矩形的内部,而且这个点一定在最里层重组的小矩形的边上,只数最里面小矩形的左下角的两条边。

一个矩形的左下角两条边和另一个矩形的右上角两条边,如果存在重叠不能保证矩形重叠,但两个矩形的左下角两条边存在重叠,则矩形一定重叠。

import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        // 矩形重叠,任意挑选一个矩形为基准,遍历其他矩形的四个角,若在此矩形内部,则认为重叠一个
        int rectCnt = sc.nextInt();
        int[] x1 = new int[rectCnt]; // 左下角横坐标
        int[] y1 = new int[rectCnt]; // 左下角纵坐标
        int[] x2 = new int[rectCnt]; // 右上角横坐标
        int[] y2 = new int[rectCnt]; // 右上角纵坐标
        for(int i = 0; i < rectCnt; i++){
            x1[i] = sc.nextInt();
        }
        for(int i = 0; i < rectCnt; i++){
            y1[i] = sc.nextInt();
        }
        for(int i = 0; i < rectCnt; i++){
            x2[i] = sc.nextInt();
        }
        for(int i = 0; i < rectCnt; i++){
            y2[i] = sc.nextInt();
        }
        int cnt = 0;
        for(int x : x1){
            for(int y : y1){
                int temp = 0;
                for(int i = 0; i < rectCnt; i++){
                    if(x1[i] <= x && x < x2[i] && y1[i] <= y && y < y2[i]){
                        temp++;
                    }
                }
                cnt = Math.max(temp, cnt);
            }
        }
        System.out.println(cnt);

    }
}

6.2 很难理解

7、网易-牛牛的闹钟

题目描述

牛牛总是睡过头,所以他定了很多闹钟,只有在闹钟响的时候他才会醒过来并且决定起不起床。
从他起床算起他需要X分钟到达教室,上课时间为当天的A时B分,请问他最晚可以什么时间起床

输入描述:

每个输入包含一个测试用例。
每个测试用例的第一行包含一个正整数,表示闹钟的数量N(N<=100)。
接下来的N行每行包含两个整数,表示这个闹钟响起的时间为Hi(0<=A<24)时Mi(0<=B<60)分。
接下来的一行包含一个整数,表示从起床算起他需要X(0<=X<=100)分钟到达教室。
接下来的一行包含两个整数,表示上课时间为A(0<=A<24)时B(0<=B<60)分。
数据保证至少有一个闹钟可以让牛牛及时到达教室。

输出描述:

输出两个整数表示牛牛最晚起床时间。

示例1

输入
3 
5 0 
6 0 
7 0 
59 
6 59

输出
6 0

7.1 利用了TreeMap的自动排序,以及保存前一个索引

import java.util.Map;
import java.util.TreeMap;
import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt(); // 闹钟数量
        int[] H = new int[N];
        int[] M = new int[N];
        for(int i = 0; i < N; i++){
            H[i] = sc.nextInt();
            M[i] = sc.nextInt();
        }
        // 小时转换为分钟,利用分钟与索引创建map
        TreeMap<Integer, Integer> map = new TreeMap<>();
        for(int i = 0; i < N; i++){
            int trans = H[i] * 60 + M[i];
            map.put(trans, i);
        }
        int X = sc.nextInt(); // 路程耗时,分钟
        int A = sc.nextInt(); //上课小时
        int B = sc.nextInt(); //上课分钟
        int comeClass  = A * 60 + B;// 上课总分钟
        int getUp = comeClass - X; // 要求起床时间
        int index = 0; // 初始化索引,起床时间
        if(map.containsKey(getUp) )
            index =  map.get(getUp); // 直接有起床闹钟就更好了
        else{ // 没有起床闹钟,那就往前找一个最近的起床闹钟
            map.put(getUp, -1); // -1是辅助值
            int preIndex = 0; // 辅助索引
            for(Map.Entry<Integer, Integer> entry : map.entrySet()){
                if(entry.getValue() == -1){
                    map.put(entry.getKey(), preIndex);
                }
                preIndex = entry.getValue(); // 保存前一次的索引
            }
            index =  map.get(getUp);
        }
        System.out.println(H[index] + " " + M[index]);
    }
}

7.2 心得,hashmap没有自动排序,需要自动排序使用TreeMap

1、网易-牛牛的背包问题

题目描述

牛牛准备参加学校组织的春游, 出发前牛牛准备往背包里装入一些零食, 牛牛的背包容量为w。
牛牛家里一共有n袋零食, 第i袋零食体积为v[i]。
牛牛想知道在总体积不超过背包容量的情况下,他一共有多少种零食放法(总体积为0也算一种放法)

输入描述:

输入包括两行
第一行为两个正整数n和w(1 <= n <= 30, 1 <= w <= 2 * 10^9),表示零食的数量和背包的容量。
第二行n个正整数v[i](0 <= v[i] <= 10^9),表示每袋零食的体积。

输出描述:

输出一个正整数, 表示牛牛一共有多少种零食放法。

示例1

输入
3 10
1 2 4

输出
8

说明
三种零食总体积小于10,于是每种零食有放入和不放入两种情况,一共有2*2*2 = 8种情况。

1.1 这种递归思路真的很巧妙,利用递归的分支选择能力

import java.util.Scanner;
public class Main{
    private static int cnt = 0;
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext() ){
            int n = sc.nextInt(); // 零食数量
            int w = sc.nextInt(); // 背包容量
            int[] v = new int[n]; // 每袋零食的体积
            long total = 0; // 背包容积w一定不超过int,但零食总体积sum会超过
            for(int i = 0; i < n; i++){
                v[i] = sc.nextInt();
                total += v[i];
            }
            if(total <= w){
                System.out.println((int)Math.pow(2, n));
            }
            else{
                // 采用递归来选择放入或不放入零食
                h(v, n, w, 0, 0);
                System.out.println(cnt);
            }
        }
        sc.close();
    }
    // 遍历过程中的零食总体积sum会超过int所以改用long,若继续使用int会出意料的错误
    public static void h(int[] v, int n, int w, long sum, int pos){
        if(pos >= n){ // 遍历完了所有零食
            if(sum <= w){
                cnt++; //这个可以采用类变量,也可以采用引用参数
            }
            return;
        }
        if(sum > w){ // 若选择部分零食过程中,总体积已超过容积,那么直接退出
            return;
        }
        h(v, n, w, sum, pos+1);// 向后遍历零食,当前零食不放入
        h(v, n, w, sum + v[pos], pos+1);// 向后遍历零食,当前零食放入
    }
}

1.2 心得,一定要注意变量合理取值范围,从而选择int,long

二进制枚举留待以后有精力再说吧

2、网易-俄罗斯方块

题目描述

小易有一个古老的游戏机,上面有着经典的游戏俄罗斯方块。
因为它比较古老,所以规则和一般的俄罗斯方块不同。
荧幕上一共有 n 列,每次都会有一个 1 x 1 的方块随机落下,在同一列中,后落下的方块会叠在先前的方块之上,当一整行方块都被占满时,这一行会被消去,并得到1分。
有一天,小易又开了一局游戏,当玩到第 m 个方块落下时他觉得太无聊就关掉了,小易希望你告诉他这局游戏他获得的分数。

输入描述:

第一行两个数 n, m
第二行 m 个数,c1, c2, ... , cm , ci 表示第 i 个方块落在第几列
其中 1 <= n, m <= 1000, 1 <= ci <= n

输出描述:

小易这局游戏获得的分数

示例1

输入
3 9
1 1 2 2 2 3 1 2 3

输出
2

2.1 这题比较简单,能通过就行

import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext() ){
            int n = sc.nextInt(); // 列数
            int m = sc.nextInt(); // 落下次数
            int[] game = new int[n];
            for(int i = 0; i < m; i++){
                int val = sc.nextInt();
                game[val-1]++;
            }
            int min = Integer.MAX_VALUE;
            for(int i = 0; i < n; i++){
                if(game[i] < min){
                    min = game[i];
                }
            }
            System.out.println(min);
        }
        sc.close();
    }
}

3、网易-瞌睡

题目描述

小易觉得高数课太无聊了,决定睡觉。不过他对课上的一些内容挺感兴趣,所以希望你在老师讲到有趣的部分的时候叫醒他一下。你知道了小易对一堂课每分钟知识点的感兴趣程度,并以分数量化,以及他在这堂课上每分钟是否会睡着,你可以叫醒他一次,这会使得他在接下来的k分钟内保持清醒。你需要选择一种方案最大化小易这堂课听到的知识点分值。

输入描述:

第一行 n, k (1 <= n, k <= 105) ,表示这堂课持续多少分钟,以及叫醒小易一次使他能够保持清醒的时间。
第二行 n 个数,a1, a2, ... , an(1 <= ai <= 104) 表示小易对每分钟知识点的感兴趣评分。
第三行 n 个数,t1, t2, ... , tn 表示每分钟小易是否清醒, 1表示清醒。

输出描述:

小易这堂课听到的知识点的最大兴趣值。

示例1

输入
6 3
1 3 5 2 5 4
1 1 0 1 0 0

输出
16

3.1 这题两层循环时间通不过,简化思路,化两层循环为一层循环的问题

1、仔细分析,最大兴趣点值可以分为两部分,一部分是固定的,即自然清醒状态,这个和叫醒没有关系。另一部分,叫醒区间的原睡眠状态的兴趣点值,这个是存在最大值的,和自然清醒状态没关系。
2、那么,现在问题是,如何在叫醒区间(滑窗思路),找出原状态为0(非清醒)的最大兴趣点值。
3、滑窗会移动,需要一个循环,且滑窗本身又有宽度,若遍历滑窗内元素,势必要嵌套一个内循环。若滑窗宽度接近于整体数组长度,这基本又是O(n^2)
4、然而,滑窗移动过程,每次是进一个元素又出一个元素,不需要遍历整个滑窗内元素,就可以得到滑窗内的累加值。这是关键突破口。

import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext() ){
            int n = sc.nextInt(); // 课堂时间
            int k = sc.nextInt(); // 清醒时间
            int[] a = new int[n]; // 每分钟知识点兴趣值
            for (int i = 0; i < n; i++) {
                a[i] = sc.nextInt();
            }
            int[] t = new int[n]; // 清醒数组
            for (int i = 0; i < n; i++) {
                t[i] = sc.nextInt();
            }
            int win_tmp = 0; // 初始化滑窗
            for(int i = 0; i < k; i++){
                if(t[i] == 0){
                    win_tmp += a[i];
                }
            }
            int sum = 0;
            int max = win_tmp; // 初始窗口最大值
            for (int i = 0; i < n; i++) {
                if(t[i] == 1){
                    sum += a[i];
                }
                else{
                    win_tmp -= a[i]; // 更新下一个滑动窗口,出窗
                }
                if(i + k < n && t[i+k] == 0){
                    win_tmp += a[i+k]; // 更新下一个滑动窗口,入窗
                }
                max = Math.max(win_tmp, max); // 当前滑窗的值max与下一个滑窗的win_tmp比较
            }
            int ret = sum + max; // 所有自然清醒1状态 与 叫醒区间内 自然睡眠0状态的兴趣最大值
            System.out.println(ret);
        }
        sc.close();
    }
}

3.2 心得,灵活使用滑窗可以帮助消除部分循环

4、网易-丰收

题目描述

又到了丰收的季节,恰逢小易去牛牛的果园里游玩。
牛牛常说他对整个果园的每个地方都了如指掌,小易不太相信,所以他想考考牛牛。
在果园里有N堆苹果,每堆苹果的数量为ai,小易希望知道从左往右数第x个苹果是属于哪一堆的。
牛牛觉得这个问题太简单,所以希望你来替他回答。

输入描述:

第一行一个数n(1 <= n <= 105)。
第二行n个数ai(1 <= ai <= 1000),表示从左往右数第i堆有多少苹果
第三行一个数m(1 <= m <= 105),表示有m次询问。
第四行m个数qi,表示小易希望知道第qi个苹果属于哪一堆。

输出描述:

m行,第i行输出第qi个苹果属于哪一堆。

示例1

输入
5
2 7 3 4 9
3
1 25 11

输出
1
5
3

4.1 这题比较搞笑,有时代码通过,有时又超时,勉强吧

import java.util.Map;
import java.util.TreeMap;
import java.util.Scanner;

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext() ){
            int n = sc.nextInt(); // n堆苹果
            int[] a =  new int[n]; // 每堆苹果个数
            TreeMap<Integer, Integer> map = new TreeMap<>();
            int sum = 0;
            for (int i = 0; i < n; i++) {
                a[i] = sc.nextInt();
                sum += a[i]; // 按累计苹果个数划分区间,map值存入区间端点和区间索引
                map.put(sum, i + 1); // 创建map,索引从1开始
            }
            int m = sc.nextInt(); // 询问次数
            int[] q = new int[m]; // 询问数组
            for (int i = 0; i < m; i++) {
                q[i] = sc.nextInt(); // 询问一次存入询问数组
                if(!map.containsKey(q[i]) ){
                    map.put(q[i], -1); // map中不存在qi就添加,值设为-1
                }
            }
            int preIndex = 0; // 初始化索引
            // 更新map的值
            for(Map.Entry<Integer, Integer> entry : map.entrySet() ){
                if(entry.getValue() == -1){
                    map.put(entry.getKey(), preIndex+1); // qi卡在前后,添加后一个的索引
                }
                else{
                    preIndex = entry.getValue();
                }
                //System.out.println(entry.getKey() + " " + entry.getValue());
            }
            // 遍历询问数组,输出苹果属于哪一堆
            for (int i = 0; i < m; i++) {
                System.out.println(map.get(q[i]) );
            }
        }
        sc.close();
    }
}

4.1 同样问题,有时代码通过,有时又超时,勉强吧,以后重置后再跑一遍

import java.util.Arrays;
import java.util.Map;
import java.util.HashMap;
import java.util.Scanner;

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext() ){
            int n = sc.nextInt(); // n堆苹果
            int[] a =  new int[n]; // 每堆苹果个数
            HashMap<Integer, Integer> map = new HashMap<>();
            int[] sarr = new int[n];
            int sum = 0;
            for (int i = 0; i < n; i++) {
                a[i] = sc.nextInt();
                sum += a[i]; // 按累计苹果个数划分区间,map值存入区间端点和区间索引
                sarr[i] = sum;
            }
            int m = sc.nextInt(); // 询问次数
            int[] q = new int[m]; // 询问数组
            for (int i = 0; i < m; i++) {
                q[i] = sc.nextInt(); // 询问一次存入询问数组
            }
            // 因为数组q是无序的,先排序后遍历
            int[] qCopy = Arrays.copyOf(q, m);
            Arrays.sort(qCopy); // 复制一份,不改变原数组顺序
            int index = 0; // 初始化索引
            for (int i = 0; i < m; i++) {
                while(index < n){
                    // 将qCopy[i]恰好卡到sarr中间
                    if(qCopy[i] <= sarr[index]){
                        map.put(qCopy[i], index+1);
                        break;
                    }
                    index++;
                }
            }
            // 遍历一遍输出
            for (int i = 0; i < m; i++) {
                System.out.println(map.get(q[i]));
            }
        }
        sc.close();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值