题目链接:网易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);
}
}
}
}