20200801猿辅导笔试记录

20200801猿辅导笔试记录


  最近比较忙,没太多时间,所以题目写的略微粗略一些。

重复的课程

输入N表示N节课,接下来输入N行每行输入课程的开始时间和结束时间,求最多的时候有几节课时间重了。
输入示例 :
4
1 4
1 2
2 3
3 4
输出:2

  这个题目描述的就很神奇,题目竟然问的是最少?这里就不纠结题目,仅供讨论。
  考虑一个时间段同时有几节课在上,在所有开始和结束的时间中遍历,如果开始一节课则同时上的课数目+1,结束一节课,则同时上的课数目-1。完整通过的人好像都是都是使用优先级队列,我觉得优先级队列在这里没必要。只需要记录一个数目即可。

#include <iostream>
#include<algorithm>
#include<vector>


using namespace std;

int main()
{
    int n;
	cin >> n;
	vector<int> start(n);
    vector<int> end(n);
    int a, b;

	for(int i=0;i<n;i++)
	{
        cin >>a>>b;
		start[i] = a;
		end[i] = b;
	}
    sort(start.begin(),start.end());
    sort(end.begin(),end.end());
    int i=0, j=0, k=0, res=0;
    while(i<n)
    {
        if (start[i]<end[j])
        {
            // 说明该在start[i]这个时段有课开了
            k += 1;
            i +=1;
            res = max(k, res);
        }
        else
        {
            j+=1;
            k-=1;
        }
    }
    cout << res << endl;
    return 0;

}

  这是我的思路,但是可能会存在瑕疵,这里把我同学AC100的代码贴上来。使用的是优先级队列,但是思想还是一样的,区别在于用变量记录窗口内课程数目还是使用优先级队列。

#include <iostream>
#include<algorithm>
#include<vector>
#include<queue>

using namespace std;

int main()
{
	int n;
	cin >> n;
	vector<pair<int,int>>range(n);
	for(int i=0;i<n;i++)
	{
		int a, b;
		cin >> a >> b;
		range[i].first = a;
		range[i].second = b;
	}
	if (n == 1)
		return 1;
	if (n == 0)
		return 0;

	sort(range.begin(),range.end());

	priority_queue<int,vector<int>,greater<int>>q;
	q.push(range[0].second);
	int ans = 1;
	for (int i = 1; i < n; i++)
	{
		
		while (q.top() <= range[i].first)
			q.pop();
		q.push(range[i].second);
		ans = max(ans, (int)q.size());
	}
	cout << ans << endl;
	return 0;
}

  考试的时候,我使用的是python,当时是比较原生,没有优化的代码。直接把start和end放在一个序列中,然后排序,判断窗口的课程数目,放在一个序列的时候依靠另一个标志来记录是开始还是结束。代码如下。

n = int(input())
res = []
for i in range(n):
    s, e  =[int(i) for i in input().split(' ')]
    res.append([s, -1])
    res.append([e, s])
res.sort(key=lambda x:x[0])

maxk = k = 0
for i in res:
    if i[1]==-1:
        k+=1
    else:
        k -=1
    maxk = max(k, maxk)

print(maxk)

  我写的两个代码的理论复杂度是一致的,无非就是python代码比较原生一些。但是这个代码,只过了55%的case。自己没找到原因,如果有人知道,或者指出我方法的问题,感激不尽。

发奖品

题目大意是这样,有个人拿到一堆奖券,但是自己只能持有一张,他需要把剩下的分给别人,每个拿到奖券的人也只能持有一张,需要继续分给别人。最后分完之后开奖,奖券对应一个奖励(会有负收益),最后需要计算每个人开奖的得分。
得分的计算需要保证,每个人只能计算自己的奖券(必须要算),以及从自己这里分出去的奖券的收益(可以选择部分)。如果要计算间接从自己这里分出去的收益,则经由中间转手送出去的收益都要被计算。举个例子就是A分出去B,B分出去了C和D,如果A要计算C或D的收益,则必须要计算中间收益B。
输入示例:
3
2 0
1 2
-1 2
输入说明:第一行表示有n张奖券,第二行到第n+1行的两个数,表示这个人的奖券收益,和奖券来源。奖券来源i表明这个人的奖券来自于第i行的这个人。0表示他是奖券的源头。如2表示奖券来源于输入第二行这个人。
输出示例: 3

  我已经把题目给大家理的很顺了。接下来就是上代码了。我一开始也看错了题目,题目要求所有人中最大的开奖得分。我以为只求第一个人的。然后一直通过0%。
  最后两分钟发现了问题,改出来如下两版代码。
  我的思想是递归,为每个奖券从这个奖券这里出去的,记为这个奖券的孩子。然后计算收益的时候,从上往下计算,如果孩子只有一张奖券,没有分出去的奖券,则看这个收益是否大于0,如果大于0则选,反之不选。如果孩子也有孩子,则递归计算孩子的收益。
  第一般代码如下:

from collections import defaultdict

n = int(input())
res = []

send = defaultdict(list)
for i in range(n):
    a, b = [int(i) for i in input().split(' ')]
    res.append(a)
    b -= 2
    send[b].append(i)
def getMaxValue(k):
    r = res[k]
    if k in send:
        for i in send[k]:
            r += getMaxValue(i)
    return max(r, 0) % 1000000003

a = 0
for i in range(n):
    a = max(getMaxValue(i), a)
print(a)

  提交后,过了50%的case,接着就回到这个老生常谈的话题,递归重复计算的问题。(注:如果只计算第一个发奖券的人,则不会有重复计算。)提交后还有一分钟,这个时候最快的方法就是加备忘录。
  第二版加了备忘录,代码如下。

from collections import defaultdict

n = int(input())
res = []

send = defaultdict(list)
for i in range(n):
    a, b = [int(i) for i in input().split(' ')]
    res.append(a)
    b -= 2
    send[b].append(i)
me = {}
def getMaxValue(k):
    if k in me:
        return me[k]
    r = res[k]
    if k in send:
        for i in send[k]:
            r += getMaxValue(i)
    me[k] =  max(r, 0) % 1000000003
    return me[k]

a = 0
for i in range(n):
    a = max(getMaxValue(i), a)
print(a)

  本以为第一版是超时,然后提交了第二版,以为没问题了,结果令我大吃一惊,发现AC还是50%。然后时间到了。我猜测这里可能是因为如果所有的中奖收益都是负数,我的代码返回的不是最大的收益,而是0。
  针对这个问题,只需要把最后返回的max移到循环内,对孩子做检查就行了,不需要对自己的收益做检查。修改后代码如下。

扫描二维码关注公众号,回复: 11481994 查看本文章
from collections import defaultdict

n = int(input())
res = []

send = defaultdict(list)
for i in range(n):
    a, b = [int(i) for i in input().split(' ')]
    res.append(a)
    b -= 2
    send[b].append(i)
me = {}
def getMaxValue(k):
    if k in me:
        return me[k]
    r = res[k]
    if k in send:
        for i in send[k]:
            r += max(getMaxValue(i), 0)
    me[k] =  r % 1000000003
    return me[k]

a = 0
for i in range(n):
    a = max(getMaxValue(i), a)
print(a)

  至于第三题,是一个简化版的后端模板语言渲染工具,思考了一阵子,发现代码量会很大,放弃了。
  虽然承认自己做的很烂,但还是想写出来留个记录,同时也为了大家讨论吧。

猜你喜欢

转载自blog.csdn.net/m0_38065572/article/details/107738214