20200802拼多多笔试题目

算法 专栏收录该内容
39 篇文章 3 订阅


  拼爹爹的题目感觉出的还是比较有水准的,不管怎么样测试用例是比较多的。直接上题目。

第一题

大致题意就是玩飞行棋,给出初始位置K(距离终点的距离),然后给出丢了n次骰子。第二行输入n个数,代表骰子的值。
如果骰子的值没用完就到了终点,则需要输出paradox。
否则,最后输出两个数,分别代表飞行棋最终的位置,和回退的次数。(如果当前的骰子点数大于当前位置到终点的距离,
多出来的部分需要回退位置。)
输入:
10 2
6 3
输出示例 1 0
输入:
10 4
6 3 3 3
输出示例 1 2
输入:
6 3
4 2 6
输出示例 paradox

  这个题比较简单,主要是注意一下边界条件,因为边界条件测试的时候k可能就是0,这个时候也要输出"paradox",另一个边界条件就是最后一个骰子掷完之后可能到终点,这个时候不能输出"paradox"。

python代码示例

k ,n = [int(i) for i in input().split(' ')]

N = [int(i) for i in input().split(' ')]
res = 0
for id,i in enumerate(N):
    if i==k and id!=n-1:
        print('paradox')
        exit(0)
    elif i<=k:
        k-=i
    else:
        k=i-k
        res +=1

print(k, res)

第二题

题目大致意思是,如果一个骰子可以通过上下,或者左右,或者前后翻转。如果通过若干次翻转后两个筛子的六个面点数
一样,则可以算作一个类骰子。
然后第一行输入一个整数n,表示有n个骰子。接下来的n行每行六个数,分别代表骰子的上下,左右,前后六个面的数字,然
后要求计算后输出,有多少类骰子,第二行输出每一类的骰子个数,需要降序排列。
示例 1:
输入:  2 
1 2 3 4 5 6 
1 2 6 5 3 4
 输出: 
1
2
示例 2:
输入: 
 3 
 1 2 3 4 5 6 
 1 2 6 5 3 4
 1 2 3 4 6 5
输出:  
2
2 1
示例 3:
输入: 
10 
2 5 1 3 4 6 
5 4 3 2 1 6 
1 4 6 2 3 5 
1 5 6 3 4 2
6 4 2 1 5 3
3 6 4 5 2 1 
1 6 3 4 2 5 
5 1 4 2 6 3 
6 2 3 1 5 4 
5 3 6 1 4 2
 输出:  
 9 
 2 1 1 1 1 1 1 1 1

  这个题算是蛮有趣的一个题目,因为很多人可能连怎么转都没搞清楚。但是这里就不细讲,可以分析一下,相对的面始终是相对的,可以把相对的面捆绑在一起。互换相对的面的时候,它们的侧面顺序是不变的。互换相对的面之后,上下会和左右颠倒,左右互换会和前后颠倒,前后互换会和左右颠倒。
  如果三组相对的面的组合一样的时候,一共会产生两种骰子,即正旋和反旋。接下来只需要判断是正旋还是反旋即可。
  把六个面中的三组中最小的数拿出来,记为x1,x2,x3,使得上,左,前(正方向)只从这三个数中产生。如果最后都把x1放在最上面,则有两种情况,x2放在最左面,x3放在最前面或者x2和x3反过来。只需要把这两种情况分清即可。
  所以先考虑把x1,x2,x3放到正方向,这个时候统计需要交换几次,这里的交换次数直接用比较统计了。然后考虑把x1放到最前面,比较一下需要交换几次,剩下的就是x2和x3的相对位置了,干脆把这个也记为一次序关系。
  最后总结出规律,如果这些情况下的交换次数为偶数,则是正旋的,交换次数为奇数,则是反旋的。然后统计两种情况分别有多少。
  用示例中的例子就是1,2,3,4,5,6显然是组内正序,不需要交换,组间也是正序。但是1,2,6,5,3,4,组内的逆序为1,组间的逆序为1,正好是一次旋转。
  好吧,我承认这种方式可能比较难以理解,但是是我考试的时候想出来的,如果大家有更好的理解,可以交流。

python代码


from collections import defaultdict
n = int(input())
res1 = defaultdict(lambda :0)
res2 = defaultdict(lambda :0)

for i in range(n):
    cur = [int(i) for i in input().split(' ')]
    o = 0
    if cur[0] < cur[1]:
        o+=1
    if cur[2]<cur[3]:
        o +=1
    if cur[4]<cur[5]:
        o+=1

    a, b, c = tuple(sorted(cur[:2])), tuple(sorted(cur[2:4])), tuple(sorted(cur[4:]))
    if a[0]<b[0] :
        o+=1
    if a[0]<c[0]:
        o+=1
    if b[0]<c[0]:
        o+=1
    if o&1:

        res1[tuple(sorted([a,b,c]))]+=1
    else:
        res2[tuple(sorted([a,b,c]))]+=1

print(len(res1)+len(res2))
for i in list(res1.values())+list(res2.values()), reverse=True):
	print(i, end=' ')

第三题

题目的大致意思是,一个人每天最多吃两顿饭,早餐和午餐,每餐只能选择一个套餐,每个套餐对应了一个热量值和美味值,这个人吃饭必须得满足两餐的总美味值高于预期,两顿饭都可以不吃。现在要求在满足美味值的条件下,热量值要最小。
输入三个数,m,n,t分别代表中餐套餐数目,晚餐套餐数目和美味值标准。要求输出最小摄入的热量值。如果怎么都达不到美味值,输出-1
示例 1:
输入:  
5 1 9
9 1
4 9
3 1
2 3
6 5
9 8 
输出:4 (解释:只需要吃一顿中餐即可) 
示例 2:
输入: 
1 1 0
3 1
2 1
输出: 0(解释,一顿都不吃)
示例 3:
输入:
3 3 10
1 1
2 5
3 7
2 4
4 8
6 9
输出: 5
示例 4:
输入: 
2 1 4
3 1
2 1
1 2
输出:
-1(解释怎么都达不到美味值,输出-1)

  思路就是把每个中餐拿出来去和晚餐配对,如果美味值大于预期,则看两者的能量和是否更小。因为晚餐已经是排好序了,我们可以倒序判断美味值是否大于预期。固定住中餐,一旦加上晚餐的美味值低于预期,内层循环立即跳出。
  这个题我只过了65,先贴代码。之后又优化外层循环提前退出和优化不对中餐进行排序,优化后代码还是65。

提交的版本

def main():
    n,m,t = [int(i) for i in input().split(' ')]
    if t ==0:
        print(0)
        return
    res = float('inf')
    mid = [[0,0]]
    night = [[0,0]]
    for _ in range(n):
        mid.append([int(i) for i in input().split(' ')])
    mid.sort(key=lambda x:x[1])
    for _ in range(m):
        night.append([int(i) for i in input().split(' ')])
    night.sort(key=lambda x:x[1])
    print(mid)
    print(night)
    if mid[-1][1] + night[-1][1] < t: 
    	# 最大的营养值达不到预期
        print(-1)
        return
    for i in range(len(mid)-1, -1, -1):
        if mid[i][1] + night[-1][1] < t:
            break
        for j in range(len(night)-1, -1, -1):
            if mid[i][1] + night[j][1] >=t:
                res = min(res ,mid[i][0] + night[j][0])
            else:
                break

    print(res)

if __name__ == '__main__':
    main()

  和过了这个题的人交流,把别人的思路也梳理一下,思想就是排序之后,如果有一个套餐能量比某些套餐能量大,但是美味值还低,这些套餐是一定都不会选的,干脆就把这些套餐剔除。这个思想的弊端在于删除这些套餐的是,需要重新建一个list,然后把不删除的放进list里。否则删除的复杂度也很大,会影响效果。改进后的代码如下。

完善版本

def deleteSupported(array):
    array.sort(key=lambda x:x[1],reverse=True)
    newArray = []
    pre = float('inf')
    for item in array:
        if item[0] < pre:
            pre = item[0]
            newArray.append(item)
    return newArray  # 注意,这里已经是倒序了,所以后面循环不需要倒序


def main():
    n,m,t = [int(i) for i in input().split(' ')]
    if t ==0:
        print(0)
        return
    res = float('inf')
    mid = [[0,0]]
    night = [[0,0]]
    for _ in range(n):
        mid.append([int(i) for i in input().split(' ')])
    mid = deleteSupported(mid)
    for _ in range(m):
        night.append([int(i) for i in input().split(' ')])
    night = deleteSupported(night)

    if mid[0][1] + night[0][1] < t:
        print(-1)
        return
    for i in range(len(mid)):
        if mid[i][1] + night[0][1] < t:
            break
        for j in range(len(night)):
            if mid[i][1] + night[j][1] >=t:
                res = min(res ,mid[i][0] + night[j][0])
            else:
                break
    print(res)

if __name__ == '__main__':
    main()

  上面的代码已经可以通过(看别人的讨论说的)。既然到这一步,中餐和晚餐已经是排好序的序列了,而且也已经剔除了用不上的一部分套餐。这样还带来了一个好处,那就是如果选定了一个值,这样就不会存在既比当前选定的这个套餐营养值高,且能量低的套餐。所以这个时候,也不用遍历整个数组,直接选定中餐后,晚餐可以二分查找了,因为只需要一个营养值恰好满足目标值的套餐。就是这个中餐对应的最优解。
  但是二分查找就是最优的了吗?并不是,现在想想。既然中餐和晚餐都排好序了。中餐的营养值较小者必然对应晚餐营养值较大者,反之亦然。那么是否可以使用双指针,这个时候营养值越小,能量肯定也越小。中餐从小往大遍历,晚餐从大往小遍历,即可找到所有可能为最小值的组合。

双指针代码

def deleteSupported(array):
    array.sort(key=lambda x:x[1],reverse=True)
    newArray = []
    pre = float('inf')
    for item in array:
        if item[0] < pre:
            pre = item[0]
            newArray.append(item)
    return newArray  # 注意,这里已经是倒序了,所以后面循环不需要倒序

def main():
    n,m,t = [int(i) for i in input().split(' ')]
    if t ==0:
        print(0)
        return
    res = float('inf')
    mid = [[0,0]]
    night = [[0,0]]
    for _ in range(n):
        mid.append([int(i) for i in input().split(' ')])
    mid = deleteSupported(mid)
    for _ in range(m):
        night.append([int(i) for i in input().split(' ')])
    night = deleteSupported(night)

    if mid[0][1] + night[0][1] < t:
        print(-1)
        return
    i, j = len(mid)-1, 0
    while j<len(night) and i>=0:
        if mid[i][1] + night[j][1] >= t:
            res = min(res, mid[i][0] + night[j][0])
            j+=1
        else:
            i -=1
    print(res)

  关于这个题想写的就这么多了,值得一提的是,有人用上了输入数据小于10W这一条信息,直接用基于counting sort的思想,把这个题的复杂度按到了 O ( n ) O(n) O(n)级别,但是掌握好通用思想就好了。

第四题

  是一道排列组合题,我自己没理顺,靠技巧过了一些case,后面搞懂了有空再贴。
  大致内容就是这样了,如果有瑕疵欢迎大家交流,也感谢大家指出我的错误。
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  

  • 4
    点赞
  • 15
    评论
  • 11
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 1024 设计师:白松林 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值