1. 程式人生 > >位元組跳動2018校招演算法方向(第一批)(程式設計題詳解)

位元組跳動2018校招演算法方向(第一批)(程式設計題詳解)

程式設計題1:

P為給定的二維平面整數點集。定義 P 中某點x,如果x滿足 P 中任意點都不在 x 的右上方區域內(橫縱座標都大於x),則稱其為“最大的”。求出所有“最大的”點的集合。(所有點的橫座標和縱座標都不重複, 座標軸範圍在[0, 1e9) 內)

如下圖:實心點為滿足條件的點的集合。請實現程式碼找到集合 P 中的所有 ”最大“ 點的集合並輸出。

思路分析:按照x座標排序,排序完用y座標構造一棵線段樹,先找出【1,n】中所有y座標的最大值(線段樹query操作),假設最大值對應的y座標為下標為a,則接下來在區間【a+1,n】中找下一個最大值,依此類推,打印出所有最大值對應的橫縱座標即可。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#define N 500005
using namespace std;
struct input{
    int x;
    int y;
}a[N];
int tree[4*N];
int ans;
bool cmp(const input& a, const input&b)
{
    return a.x<b.x;
}
void build(int l, int r, int k)
{
    if(l==r){
        tree[k]=a[l-1].y;
        return;
    }
    int m=l+((r-l)>>1);
    build(l,m,k<<1);
    build(m+1,r,k<<1|1);
    tree[k]=max(tree[k<<1], tree[k<<1|1]);
}
void query(int L, int R, int l,int r, int k)
{
    if(L<=l&&r<=R)
    {
        ans = max(ans, tree[k]);
        return;
    }
    int m=l+((r-l)>>1);
    if(m>=L)query(L,R,l,m,k<<1);
    if(m<R)query(L,R,m+1,r,k<<1|1);
}
int main()
{
    int n,x,y;
    scanf("%d",&n);
    for(int i=0;i<n;++i)
    {
        scanf("%d%d",&x,&y);
        a[i].x=x;
        a[i].y=y;
    }
    sort(a,a+n,cmp);
    build(1, n, 1);
    int start = 0;
    while(start<n)
    {
        ans = a[start].y;
        query(start+1,n,1,n,1);
        for(int i=start;i<n;++i)
        {
            if(a[i].y==ans)
            {
                printf("%d %d\n",a[i].x, a[i].y);
                start=i+1;
                break;
            }
        }
    }
    return 0;
}

程式設計題2:

給定一個數組序列, 需要求選出一個區間, 使得該區間是所有區間中經過如下計算的值最大的一個:

區間中的最小數 * 區間所有數的和最後程式輸出經過計算後的最大值即可,不需要輸出具體的區間。如給定序列  [6 2 1]則根據上述公式, 可得到所有可以選定各個區間的計算值:

[6] = 6 * 6 = 36;

[2] = 2 * 2 = 4;

[1] = 1 * 1 = 1;

[6,2] = 2 * 8 = 16;

[2,1] = 1 * 3 = 3;

[6, 2, 1] = 1 * 9 = 9;

從上述計算可見選定區間 [6] ,計算值為 36, 則程式輸出為 36。

區間內的所有數字都在[0, 100]的範圍內;

思路分析:簡單題,因為數字範圍在【0,100】之間,而0對應的乘積一定是0,所以只需遍歷1到100。假設遍歷到x,就把所有數按照x拆成多份,其中每份的值都必須大於等於x,其中和最大的那一份就是x對應的乘積最大值,答案就是所有乘積最大值中最大的那個。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#define N 500005
using namespace std;
int a[N];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;++i)
    {
        scanf("%d",&a[i]);
    }
    long long ans = 0;
    for(int i=1;i<=100;++i)
    {
        long long sum = 0;
        for(int j=0;j<n;++j)
        {
            if(a[j]>=i)sum+=a[j];
            else
            {
                ans = max(ans, sum*i);
                sum = 0;
            }
        }
        ans = max(ans, sum*i);
    }
    printf("%lld\n",ans);
    return 0;
}

程式設計題3:

產品經理(PM)有很多好的idea,而這些idea需要程式設計師實現。現在有N個PM,在某個時間會想出一個 idea,每個 idea 有提出時間、所需時間和優先等級。對於一個PM來說,最想實現的idea首先考慮優先等級高的,相同的情況下優先所需時間最小的,還相同的情況下選擇最早想出的,沒有 PM 會在同一時刻提出兩個 idea。

同時有M個程式設計師,每個程式設計師空閒的時候就會檢視每個PM尚未執行並且最想完成的一個idea,然後從中挑選出所需時間最小的一個idea獨立實現,如果所需時間相同則選擇PM序號最小的。直到完成了idea才會重複上述操作。如果有多個同時處於空閒狀態的程式設計師,那麼他們會依次進行檢視idea的操作。

求每個idea實現的時間。

輸入第一行三個數N、M、P,分別表示有N個PM,M個程式設計師,P個idea。隨後有P行,每行有4個數字,分別是PM序號、提出時間、優先等級和所需時間。輸出P行,分別表示每個idea實現的時間點。

思路分析:不需要用到什麼高階資料結構,就用1個優先佇列陣列存每個PM在當前時間點已經提出的需求,1個優先佇列存所有程式設計師空閒的時間(這個佇列的大小一直是M),其他細節看程式碼就行,不難理解。

#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<algorithm>
#define N 3005
using namespace std;
struct node{
    int pm;
    int start;
    int pri;
    int need;
    int task_id;
}no[N];
bool cmp(const node& a, const node& b)
{
    return a.start<b.start;
}
struct CmpStruct{
    bool operator()(node a, node b)
    {
        return a.pri<b.pri||(a.pri==b.pri&&a.need>b.need)||
            (a.pri==b.pri&&a.need==b.need&&a.start>b.start);
    }
};
vector<node> vec[N];
priority_queue<node, vector<node>, CmpStruct> q[N];
priority_queue<int, vector<int>, greater<int> > q_time;
int ans[N];
int main()
{
    int n,m,p;
    scanf("%d%d%d",&n,&m,&p);
    for(int i=0;i<p;++i)
    {
        scanf("%d%d%d%d",&no[i].pm, &no[i].start, &no[i].pri, &no[i].need);
        no[i].task_id=i+1;
    }
    sort(no, no+p, cmp);
 
    int start_task_id = 0;
    for(int i=0;i<m;++i)q_time.push(1);
    int start_time = q_time.top();
    int task_finish_cnt = 0;
    while(1)
    {
        int i=start_task_id;
        for(;i<p;++i)
        {
            if(no[i].start<=start_time)q[no[i].pm].push(no[i]);
            else break;
        }
        start_task_id=i;
 
        q_time.pop();
        int minn = 3001;
        int pm_id = 0;
        for(int i=1;i<=n;++i)
        {
            if(!q[i].empty() && q[i].top().need<minn)
            {
                minn=q[i].top().need;
                pm_id = i;
            }
        }
        if(pm_id>0)
        {
            int finish_time = start_time+q[pm_id].top().need;
            ans[q[pm_id].top().task_id]=finish_time;
            task_finish_cnt++;
            if(task_finish_cnt==p)break;
            q_time.push(finish_time);
            start_time = q_time.top();
            q[pm_id].pop();
        }
        else
        {
            q_time.push(start_time+1);
            start_time = q_time.top();
        }
    }
    for(int i=1;i<=p;++i)
    {
        printf("%d\n",ans[i]);
    }
    return 0;
}