位元組跳動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;
}