4.11 网易互娱2020届校招补录笔试-服务端笔经-

总体

职位是服务端开发工程师
4个编程题, 3AC, 就差最后一题, 最后一题70%没往自己最长上升子序列算法写错了上想, 思路想歪了, 浪费了半小时(不过u1s1题目本身没讲清楚)
有些题难度感觉和分值对不上, 希望能交流交流

第一题

描述

给两个字符串形式储存的九进制数(可能包括小数部分), 求两数之和, 用字符串形式输出

思路

建议参考leetcode 2 或者 leetcode 415
time O(n) space O(n)

代码

#
# 接收两个表示9进制数的字符串,返回表示它们相加后的9进制数的字符串
# @param num1 string字符串 第一个加数
# @param num2 string字符串 第二个加数
# @return string字符串
#
class Solution:
    def add(self , num1 , num2 ):
        p1 = num1.find('.')
        p2 = num2.find('.')
        if p1!=-1 or p2!=-1:
            if p1==-1 and p2!=-1:
                num1,num2=num1,num2
            if p1!=-1 and p2==-1:
                int_num1, par_num1 = num1.split('.')
                return self.int_add(int_num1,num2)+'.'+par_num1
            if p1!=-1 and p2!=-1:
                int_num1, par_num1 = num1.split('.')
                int_num2, par_num2 = num2.split('.')
                l1 = len(par_num1)
                l2 = len(par_num2)
                l = max(l1,l2)
                par_num1+='0'*(l-l1)
                par_num2+='0'*(l-l2)
                sa = self.int_add(par_num1,par_num2)
                sb = self.int_add(int_num1,int_num2)
                if len(sa)>l:
                    
                    return self.int_add(sb,"1") + '.' + sa[1:]
                else:
                    return sb+'.'+sa
        else:
            return self.int_add(num1,num2)
    
    def int_add(self, num1, num2):
        n1 = len(num1)
        n2 = len(num2)
        s1 = n1 - 1
        s2 = n2 - 1
        res = []
        car = 0
        while s1>=0 or s2>=0 or car>0:
            if s1>=0:
                car += int(num1[s1])
                s1-=1
            if s2>=0:
                car += int(num2[s2])
                s2-=1
            d = car%9
            res.append(str(d))
            car//=9
        return "".join(reversed(res))
        

第二题

描述

给一个数组W表示n个人的等级
给一个数组T表示n个任务的难度
一个人的等级>=一个任务的难度时, 这个人才能解决这个任务
一个人只能解决一个任务
问 解决所有任务的分配人手的方案的总数

算法

现将W,T升序排序
dp思想, dp[i] 表示只有前i+1个人时, 总的分配方案数
time O(nlgn) aux space O(1)
计算dp[i]时, 加入W[i]这个人, 如果他处理不了T[i]那么谁也处理不了,
否则, 先让W[i]处理T[i], 然后找出所有能处理T[i]的人,
将W[i]与这个人互换又能产生一种新方案

代码

import bisect
n = int(input())
W = list(map(lambda x:int(x), input().split()))
T = list(map(lambda x:int(x), input().split()))
M = int(input())
W.sort()
T.sort()

def main():
    dp = 1
    for i in range(n):
        if W[i]<T[i]:
            return 0
        # 和 c++ std::lower_bound 一样, 二分查找第一个大于等于目标值的元素的索引
        can = i - bisect.bisect_left(W,T[i]) + 1
        dp = dp*can%M
    return dp

print(main())

第三题

描述

算法

数据量太小了, 就是暴力也可以说dfs, 而且没优化
J表示判断条件的总数
time space O(n*m) (1<=n,m<=7)
现在回想起来运气很好
如果利用好为Y的判断条件, 至少总时间复杂度上界 JY表示为Y的条件数
具体可以参考leetcode 37 Sudoku solver
用一个二维数组维护一个像题目输出的那种矩阵,
横行每一队伍用一个set维护已经存在的选手, 这样在选人的时候, 可以O(1)解决为N的判断条件(判断条件用hashmap[(i,j)]=(p,q)存, 如果i>p要交换一下, 保证竖着搜能先搜到hashmap中的value对应的人)
为Y的判断条件也用hashmap[(i,j)]=(p,q), 如果i>p要交换一下, 这样在选到 第i支队伍第j个选手的时候, 查看横行是否已经存在这名选手需要的人, 也是O(1)
竖行每一个职业还剩下谁再用一个set维护, 每次选人就从这个set中选
先搜第一支队伍第一个人, 再搜第二支队伍第一个人, ..., 再搜第一支队伍第二个人, ..., 竖着搜(也可以直接假定输出矩阵的第一列是ABCD, 这样又能少点搜索空间)
回溯的时候, 竖行横行的set维护直接删就行了
我数独代码就是9行,9列,9宫都用一个set维护, 40行搞定
原题目给的队伍名单
ABCD
efgh
IJKL
要求输出的矩阵:
AeJ
BhK
CgI
DfL

代码

下面的代码直接枚举出了所有搜索空间, 用笛卡尔积加上全排列枚举出了所有可能的m*n矩阵的状态
n,m = map(lambda x:int(x), input().split())

job_player = [None]*n
for i in range(n):
    job_player[i] = list(input())

ruleY=[]
ruleN=[]
# print(job_player)
while True:
    
    i,j,c,p,q = input().split()
    if int(i)==0:
        break

    if c=='Y':
        ruleY.append(tuple(map(lambda x:int(x)-1,(i,j,p,q))))
    else:
        ruleN.append(tuple(map(lambda x:int(x)-1,(i,j,p,q))))

from itertools import permutations
from itertools import product

def judge(base):
    for i,j,p,q in ruleY:
        if base[i].index(j)!=base[p].index(q):
            return False
    for i,j,p,q in ruleN:
        if base[i].index(j)==base[p].index(q):
            return False
    return True

def myprint(base):
    for i in range(m):
        for j in range(n):
            print(job_player[j][base[j][i]],end='')
        print()

def brute_force():
    for base in product(permutations(range(m)),repeat=n):
        if judge(base):
            myprint(base)
            break

brute_force()

第四题

描述

n个盒子每个盒子有长宽高三种整数值属性, 一个盒子能放在另一个盒子里面当且仅当这个盒子长宽高都小于另一个盒子
盒子不能翻转,
也不能绕z轴旋转,只能平移,  所有盒子一开始长边对齐x轴, 宽边对齐y轴, 高边对齐z轴, x,y,z轴正交(这条是我脑补的问考官也不说, 如果不能旋转那么这题就是leetcode300, 从ac同学的代码看也是如此)
一个盒子a里面只能放一个盒子b(不包括b盒子里面的盒子)
假如一个盒子里面最多能有k个盒子(包括盒子内的盒子) 输出k+1

算法

O(n^2) 空间O(n)
思想可参考leetcode 300: 最长上升子序列的长度
排序只需要保证排在后面的盒子不能被前面的盒子装, 然后就是标准的dp思想

如果盒子只有两个维度, 如leetcode 354, 通过一些技巧, 是能够O(nlgn)解决的, 但是盒子有三个维度我不知道有没有O(nlgn)写法
同时, 如果盒子可以旋转翻转, 这就是变成了DAG最长路问题

能100%AC的代码

class Solution:
    def maxBoxes(self , boxes ):
        boxes.sort()
        n=len(boxes)
        def can_be_contain(box1, box2):
            return all(box1[i]<box2[i] for i in range(3))

        dp = [1]*(1+n) # dp[i]表示以索引为i-1的盒子作为最外层盒子, 最多能打包多少盒子
        dp[0]=0
        for i in range(1, n+1):
            for j in range(i):
                if can_be_contain(boxes[j-1], boxes[i-1]):
                    dp[i] = max(dp[i], 1+dp[j])
        return max(dp) # 我考的时候return了dp[n-1]


#网易互娱##笔试题目##笔经#
全部评论
第三题ac太强了。第四题错的地方跟我一开始一样,虽然排过序,但是最后一个能打包的不一定是最多的,可以看看我的帖子。
2 回复 分享
发布于 2020-04-11 22:04
非常感谢楼主的分享,学习到很多了!!
1 回复 分享
发布于 2020-04-13 12:06
第三题,这个复杂度,极限情况会超时吧?说明样例没有极限情况?
点赞 回复 分享
发布于 2020-04-11 22:12
看复杂度第三题是直接枚举全排列吗?
点赞 回复 分享
发布于 2020-04-12 02:16
收到面试通知了吗
点赞 回复 分享
发布于 2020-04-13 22:13

相关推荐

点赞 评论 收藏
分享
评论
9
29
分享
牛客网
牛客企业服务