牛客网—网易2019实习生招聘编程题

题目链接:网易2019实习生招聘

第一题 牛牛找工作

链接:https://www.nowcoder.com/questionTerminal/46e837a4ea9144f5ad2021658cb54c4d

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

输入描述:
每个输入包含一个测试用例。
每个测试用例的第一行包含两个正整数,分别表示工作的数量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

解题思路:

最直观的方法是使用双重循环,但是时间复杂度为O(n^2),超时了。。。。

将工作难度和报酬根据难度进行排序,然后将报酬更新为当前难度下的最高报酬,因为难度和报酬不一定是成正比的,所以为得到更高的报酬,无法根据初始难度来获得最高的报酬。
如初始难度和报酬排序为:
1 100
2 10
3 1000
10 500
更新后为:
1 100
2 100
3 1000
4 1000

然后选择和自身能力最接近的工作难度所得报酬即为所求。

代码:
import java.util.*;

public class Main{
    public static void main(String[] args){
        //使用Scanner类进行输入
        Scanner in = new Scanner(System.in);
        int workNum = in.nextInt();
        int partnerNum = in.nextInt();
        //将工作难度和报酬保存到work二维数组中
        int[][] work = new int[workNum][2];
        for(int i = 0;i < workNum;i++){
            work[i][0] = in.nextInt();
            work[i][1] = in.nextInt();
        }
        //保存伙伴能力到partnerAi数组中
        int[] partnerAi = new int[partnerNum];
        for(int i = 0;i<partnerNum;i++){
            partnerAi[i] = in.nextInt();
        }
        //根据工作难度,对工作进行排序,这里使用jdk1.8的lambda
        Arrays.sort(work, ((o1, o2) -> o1[0]-o2[0]));

        //更新工作报酬为当前难度最高报酬,并将工作放置到TreeMap中
        TreeMap<Integer, Integer> map = new TreeMap<Integer, Integer>();
        map.put(work[0][0], work[0][1]);

        for(int i = 1;i<workNum;i++){
            //更新报酬
            work[i][1] = Math.max(work[i-1][1], work[i][1]);
            map.put(work[i][0], work[i][1]);
        }

        for(int i = 0;i<partnerNum;i++){
            //TreeMap中的floorKey方法即是找到与当前key最接近的key
            Integer k = map.floorKey(partnerAi[i]);
            if(k != null)
                System.out.println(map.get(k));
            else
                System.out.println(0);
        }
    }

}

第二题 被3整除

链接:https://www.nowcoder.com/questionTerminal/51dcb4eef6004f6f8f44d927463ad5e8

小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整除。

解题思路:

一个数字,判断是否被3整除,可以将每个位上的数字相加,如果和可以被3整除,那么这个数字便可以被3整除,这种方法最直观,但是同样超时了。。。。

参考:http://www.cnblogs.com/Kiven5197/p/8716537.html

通过找规律可以看出,这个数列中的每个数是有1,2,3….组成的,所以要判断第i个数是否能被3整除,可以通过(1+2+3…+i)/3是否等于0来判断,这里有1,2,3,4…除以3取余分别为1,2,0,1,2,0,1,2,0

这个数列是否能被3整除为:false,true,true,false,true,true,false,true,true…..即每3个数字一个循环。
所以前i个数字中:
如果i%3 == 0,则能被3整除的数字个数为i/3 *2;
如果i%3 == 1,则能被3整除的数字的个数为i/3 * 2;
如果i%3 == 2,则能被3整除的数字的个数为i/3 *2 +1;

import java.util.*;

public class Main{
    public static void main(String[] args){
        //输入数据
        Scanner in = new Scanner(System.in);
        int l = in.nextInt();
        int r = in.nextInt();

        System.out.println(calThree(r) - calThree(l-1));
    }

    public static int calThree(int num){
        if(num%3 == 1 || num%3==0){
            return num/3*2;
        }
        else
            return num/3*2+1;
    }
}

第三题 安置路灯

链接:https://www.nowcoder.com/questionTerminal/3a3577b9d3294fb7845b96a9cd2e099c

小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个位置中有一个位置为“.”,即需要照亮,就需要一盏灯,所以设置一个指针,当指向“X”时跳过,当指向“.”时,无论其后面的两个位置是什么,均需要设置一盏灯,并将指针指向的位置+3。

代码:
import java.util.*;

public class Main{
    public static void main(String[] args){
        //输入,num代表测试用例的数量
        Scanner in = new Scanner(System.in);
        int num = in.nextInt();

        while(num > 0){
            int roadLen = in.nextInt(); //路长
            String road = in.next();  //需要照亮的路况
            int re = 0;   //需要路灯的数量
            int i = 0;    //指针指向每一格

            while(i < roadLen){
                if(road.charAt(i) == 'X')
                    i++;
                else{
                    re++;
                    i +=3;
                }
            }
            num--;
            System.out.println(re);
        }

    }
}

第四题 迷路的牛牛

链接:https://www.nowcoder.com/questionTerminal/fc72d3493d7e4be883e931d507352a4a

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

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

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

示例1
输入
3
LRR
输出
E

解题思路:

向右转为顺时针转1步,向左转为逆时针转1步,即顺时针转3步,那么将东西南北存储为字符串str = “NESW”,使用reCount记录每次顺时针转动的步数,每向右转加1,每向左转加3,每4步一个循环,所以最后需要reCount%4。

代码:
import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner in = new Scanner(System.in);
        //转弯的次数
        int n = in.nextInt();
        //记录东西南北方向的字符串
        String str = "NESW";
        //记录每次转弯的方向
        String dir = in.next();
        //记录顺时针转动的次数
        int reCount = 0;
        for(int i = 0;i<n;i++){
            if(dir.charAt(i) == 'L')
                reCount += 3;
            else
                reCount++;
        }

        reCount = reCount%4;
        System.out.println(str.charAt(reCount));
    }
}

第五题 数对

链接:https://www.nowcoder.com/questionTerminal/bac5a2372e204b2ab04cc437db76dc4f

牛牛以前在老师那里得到了一个正整数数对(x, y), 牛牛忘记他们具体是多少了。

但是牛牛记得老师告诉过他x和y均不大于n, 并且x除以y的余数大于等于k。
牛牛希望你能帮他计算一共有多少个可能的数对。

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

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

示例1
输入
5 2
输出
7

说明
满足条件的数对有(2,3),(2,4),(2,5),(3,4),(3,5),(4,5),(5,3)

解题思路:

首先最简单易想到的方法就是暴力破解,但又超时类 。。。。。

参考:https://my.oschina.net/liyurong/blog/1788475

当k==0时,那么下x,y取<=n的正整数均可,所以满足的数对的数量为n*n;
当k>0时,那么x的取值范围为[1,n],可以将n分成n/y个整区间,每个区间内分别为(1,2…y-2,y-1,y)(y+1, y+2….2y)……
那么对于在每个区间内的数可以代表x,每个区间上除去最后一个数,第i个数%y总是等于i的,所以每个区间上%y后>=k的数的个数为y-k,所以在整区间内,x的个数为n/y*(y-k)。
当n%y>=k时,最后的存在的非整区间中也有满足条件的值,非整区间的数字的个数为n%y,其中除以y取余后>=k的个数为n%y-(k-1)个。

java中int类型占32位,所以取值范围为-2^31~2^31-1即(-2147483648,2147483647)

代码实现:
import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner in = new Scanner(System.in);
        //虽然n的取值范围为1~10^5次方,但是多种情况相加后得到的总数可能会超过2^31-1,所以这里直接使用Long类型
        Long n = in.nextLong();
        Long k = in.nextLong();
        Long reNum = 0L;

        /*暴力破解,超时了
        for(int i=1; i<n+1;i++){
            for(int j=1;j<n+1;j++){
                if(i%j>=k)
                    reNum++;
            }
        }*/

        Long y;

        if(k==0){
            reNum = n*n;
        }
        else{
            //既然余数为k,那么y的取值范围应为[k+1, n]
            for(y = k+1;y<=n;y++){
                reNum += (n/y) * (y-k);
                if(n%y>=k){
                    reNum += n%y - k + 1;
                }
            }    
        }
        System.out.println(reNum);
    }
}

第六题 矩形重叠

链接:https://www.nowcoder.com/questionTerminal/a22dd98b3d224f2bb89142f8acc2fe57

平面内有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

解题思路:

通过暴力判断所有矩形的点分别在多少个矩形内(点在矩形内,则说明有重叠区域),从中选择最大的,即为所求。

代码实现:
import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        //左下角横坐标
        int[] x1 = new int[n];
        //左下角纵坐标
        int[] y1 = new int[n];
        //右上角横坐标
        int[] x2 = new int[n];
        //右上角纵坐标
        int[] y2 = new int[n];

        //存放矩形点的横坐标
        ArrayList<Integer> xx = new ArrayList<Integer>();
        //存放矩形点的纵坐标
        ArrayList<Integer> yy = new ArrayList<Integer>();

        //输入左下角横坐标,并存入xx
        for(int i = 0;i<n;i++){
            x1[i] = in.nextInt();
            xx.add(x1[i]);
        }
        //输入左下角纵坐标,并存入yy
        for(int i = 0;i<n;i++){
            y1[i] = in.nextInt();
            yy.add(y1[i]);
        }
        //输出右上角横坐标,并存入xx
        for(int i = 0;i<n;i++){
            x2[i] = in.nextInt();
            xx.add(x2[i]);
        }
        //输入右上角纵坐标,并存入yy
        for(int i = 0;i<n;i++){
            y2[i] = in.nextInt();
            yy.add(y2[i]);
        }
        //点在矩形内最多的个数
        int re = 0;
        //循环遍历,外两圈为矩形的点,最内圈为循环每个矩形
        for(int x:xx){
            for(int y:yy){
                int count = 0;
                for(int i=0;i<n;i++){
                    //将矩形中的点分别与每个矩形的左下角和右上角比较,判断是否在矩形内
                    if(x>x1[i]&&y>y1[i]&&x<=x2[i]&&y<=y2[i])
                        count++;
                }
                re = Math.max(re,count);
            }
        }
        System.out.println(re);
    }
}

第七题 牛牛的闹钟

链接:https://www.nowcoder.com/questionTerminal/9173e83d1774462f81255a26feafd7c6

牛牛总是睡过头,所以他定了很多闹钟,只有在闹钟响的时候他才会醒过来并且决定起不起床。从他起床算起他需要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

解题思路1:

将闹铃排序后并与牛牛到达教室的所需时间相加,求得其中最接近上课时间的值即可。

代码实现1:
import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        //设置存放闹钟时间的Clock数组
        Clock[] clock = new Clock[n];
        //输入闹钟时间
        for(int i = 0;i<n;i++){
            int H = in.nextInt();
            int B = in.nextInt();
            Clock c = new Clock(H,B);
            clock[i] = c;
        }
        //xTime为达到教室所需时间,将其同样转化为Clock类
        int xTime = in.nextInt();
        Clock x = new Clock(xTime/60,xTime%60);
        //输入上课时间,并转化为Clock类
        int hClass = in.nextInt();
        int bClass = in.nextInt();
        Clock goClass = new Clock(hClass,bClass);

        //对闹钟时间进行排序
        Arrays.sort(clock);

        for(int i = n-1;i>-1;i--){

//倒序比较闹钟时间+准备时间和上课时间比较            if(clock[i].add(x).compareTo(goClass)==0||clock[i].add(x).compareTo(goClass)==-1){
                System.out.println(clock[i].H + " " + clock[i].B);
                break;
            }

        }
    }
}
//编写Clock类并实现Comparable接口,并重写compareTo方法,注意的是在接口名Comparable后使用泛型
class Clock implements Comparable<Clock>{
    int H;
    int B;
    Clock(int H, int B){
        this.H = H;
        this.B = B;
    }
    //Clock的方法,进行时间相加
    public Clock add(Clock c){
        int reB = (c.B + this.B)%60;
        int reH = c.H + this.H + (c.B + this.B)/60;
        Clock re = new Clock(reH, reB);
        return re;
    }

    @Override
    //通过比较时针和分针,判断时间大小重写compareTo方法
    public int compareTo(Clock c) {
        if(this.H > c.H)
            return 1;
        if(this.H == c.H)
            if(this.B > c.B)
                return 1;
            else{
                if(this.B == c.B)
                    return 0;
                else
                    return -1;
            }
        else
            return -1;
    }

}
解题思路2:

在网上看到其他人的解题思路,代码长度和时间复杂度都比自己的低,所以特此借鉴记录下。
参考:https://blog.csdn.net/flushhip/article/details/79721659

将时间都转换为分钟的形式,方便进行计算,然后根据上课时间和准备时间计算出牛牛最晚起床时间,在闹钟中通过二分查找算法找出上界。

代码实现2:
import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int[] clock = new int[n];
        for(int i = 0;i<n;i++){
            clock[i] = in.nextInt()*60 + in.nextInt();
        }

        Arrays.sort(clock);

        int xTime = in.nextInt();
        int classTime = in.nextInt()*60+ in.nextInt();

        int getUp = classTime - xTime;

        System.out.println(bs(clock, getUp)/60 + " " + bs(clock, getUp)%60);
    }
    //二分查找求上界
    public static int bs(int[] c, int t){
        int len = c.length;
        int left = 0;
        int right = len;
        while(left < right){
            int mid = (left+right)/2;
            if(c[mid]>t)
                right = mid;
            else
                left = mid+1;
       }
        return c[left-1];
    }
}

第八题 牛牛的背包

链接:https://www.nowcoder.com/questionTerminal/bf877f837467488692be703735db84e6

牛牛准备参加学校组织的春游, 出发前牛牛准备往背包里装入一些零食, 牛牛的背包容量为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种情况。

解题思路:

参考:https://www.nowcoder.com/questionTerminal/bf877f837467488692be703735db84e6

对于每种零食,有两种选择,放入或者不放入,所以通过使用深度优先搜索,递归实现。

代码实现:
import java.util.*;

public class Main{
    static int count = 0;
    public static void main(String[] args){
        Scanner in = new Scanner(System.in);
        int n = in.nextInt(); //零食数量
        int w = in.nextInt(); //背包体积
        int[] v = new int[n]; //每个零食的体积
        long sumv = 0L;       //零食体积之和,注意虽然每个零食的体积<2*10^9,但是所有零食之和很可能就超过int表示的数值范围了,所以使用long类型
        for(int i=0;i<n;i++){
            v[i] = in.nextInt();
            sumv += v[i];
        }
        //当所有零食的体积小于背包体积时,所有零食都可以放入
        if(sumv <= w)
            System.out.println((int)Math.pow(2,n));
        else{
            dfs(0,0,w,v,n);
            System.out.println(count+1);
        }
    }

    /*深度搜索,
    sum为当前待要加入背包中零食的体积,同样要使用long类型;
    cur为当前正在考虑的是否能够加入到背包中零食的号码;
    w为背包的体积;
    v为零食的体积;
    n为零食的数量;
    */
    public static void dfs(long sum, int cur, int w, int[] v, int n){
        //在当前考虑的零食的号码小于总零食的数量才能进行
        if(cur < n){
            //如果待加入到背包中的零食体积和超过了背包的体积,则直接返回
            if(sum > w)
                return ;
            //当前号码为cur的零食不加入到背包中,所以cur+1,但是sum不变
            dfs(sum, cur+1,w,v,n);
            //如果待加入到背包中的零食体积+当前零食体积<=背包体积,便可以将当前零食加入
            if(sum + v[cur]<=w){
                count ++;
                //cur号零食已经加入背包,分析下一个号码的零食情况
                dfs(sum+v[cur],cur+1,w,v,n);
            }
        }

    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值