1. 程式人生 > >牛客網—網易2019實習生招聘程式設計題

牛客網—網易2019實習生招聘程式設計題

第一題 牛牛找工作

為了找到自己滿意的工作,牛牛收集了每種工作的難度和報酬。牛牛選工作的標準是在難度不超過自身能力值的情況下,牛牛選擇報酬最高的工作。在牛牛選定了自己的工作後,牛牛的小夥伴們來找牛牛幫忙選工作,牛牛依然使用自己的標準來幫助小夥伴們。牛牛的小夥伴太多了,於是他只好把這個任務交給了你。

輸入描述:
每個輸入包含一個測試用例。
每個測試用例的第一行包含兩個正整數,分別表示工作的數量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整除

小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整除,這種方法最直觀,但是同樣超時了。。。。

通過找規律可以看出,這個數列中的每個數是有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;
    }
}

第三題 安置路燈

小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);
        }

    }
}

第四題 迷路的牛牛

牛牛去犇犇老師家補課,出門的時候面向北方,但是現在他迷路了。雖然他手裡有一張地圖,但是他需要知道自己面向哪個方向,請你幫幫他。

輸入描述:
每個輸入包含一個測試用例。
每個測試用例的第一行包含一個正整數,表示轉方向的次數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));
    }
}

第五題 數對

牛牛以前在老師那裡得到了一個正整數數對(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)

解題思路:

首先最簡單易想到的方法就是暴力破解,但又超時類 。。。。。

當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);
    }
}

第六題 矩形重疊

平面內有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);
    }
}

第七題 牛牛的鬧鐘

牛牛總是睡過頭,所以他定了很多鬧鐘,只有在鬧鐘響的時候他才會醒過來並且決定起不起床。從他起床算起他需要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:

將時間都轉換為分鐘的形式,方便進行計算,然後根據上課時間和準備時間計算出牛牛最晚起床時間,在鬧鐘中通過二分查詢演算法找出上界。

程式碼實現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];
    }
}

第八題 牛牛的揹包

牛牛準備參加學校組織的春遊, 出發前牛牛準備往揹包裡裝入一些零食, 牛牛的揹包容量為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種情況。

解題思路:

對於每種零食,有兩種選擇,放入或者不放入,所以通過使用深度優先搜尋,遞迴實現。

程式碼實現:

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);
            }
        }

    }
}