VIVO校招提前批算法工程师笔试题目 2019/6/4

总共有三道题:

  1. 很简单的一道题,给A,B两个数组,输出出现在A中而没有出现在B中的元素,输出元素前后顺序不变,遍历一遍就OK了。
  2. 反转链表的第M个至第N个元素
  3. 0-1 背包
第一题

第一题很简单,直接遍历就行,在笔试的时候,我没有检查输入= =!

def fun(list_A,list_B):
    if len(list_A) < 1:return []
    if len(list_B) < 1:return list_A
    res = []
    for item in list_A:
        if item not in list_B:
            res.append(item)
    return res

性能分析:空间复杂度 O ( n ) O(n) O(n),时间复杂度 O ( n 2 ) O(n^2) O(n2)

第二题

这一题其实并不难,我在笔试的时候觉得比较坑的是VIVO的python调试只显示你的结果和答案是不是一致,而不显示你的输出,因此我当时边界条件没有确定好,所以这道题跪了。。。

class Node:
    next = None
    val = None
    
def reversed_m_to_n(pHead,m,n):
    assert n>=m
    if pHead == None:return pHead
    pNode = pHead
    for i in range(m-2): # 这个m-2在笔试的时候写成了m-1。。。
        # 如果m超出了链表的长度,返回空
        if pNode.next == None:return None 
        pNode = pNode.next
    # 第m个节点的前一个节点,记录这个节点方便后面把它的next设成第n个节点
    m_minus_1 = pNode
    pNode = pNode.next
    # 记录第m个节点,后面把它的next设置成第n+1个节点
    mth_Node = pNode
    pPrev = pNode
    pNode = pNode.next
    pNext = pNode.next
    for i in range(n-m):
        pNode.next = pPrev
        pPrev = pNode
        pNode = pNext
        # 如果n超过了链表长度,直接打断,并反转第m个至链表尾
        if pNode.next == None:
            break
        pNext = pNode.next
    # 此时pNode就是第n+1个节点了,pPrev是第n个节点
    m_minus_1.next = pPrev
    mth_Node.next = pNode
    return pHead

def create_liked_list(string):
    pHead = Node()
    length = len(string)
    if length < 1:raise Exception('please enter an non-empty string!')
    # 这一步必须有,因为要返回head,不能丢失head
    pNode = pHead
    for i in range(length):
        pNode.val = string[i]
        pNode.next = Node()
        pNode = pNode.next
    return pHead

def print_linked_list(pHead):
    # if pHead == None:
        # return
    while(pHead != None and pHead.next != None):
        print(pHead.val,end='\t')
        pHead = pHead.next
    print()

上面这个代码测试,已测试以下情形

  1. 正常情况 正常输出现象
  2. n>m>链表长度 返回空,输出空
  3. n>链表长度>m 返回第m个至链表尾的反转
m = 4
n = 7
head = create_liked_list('89743251')
print('raw linked list:')
print_linked_list(head)
head = reversed_m_to_n(head,m,n)
print("reversed %dth to %dth element's linked list:"%(m,n))
print_linked_list(head)

性能分析:空间复杂度 O ( 1 ) O(1) O(1),时间复杂度 O ( n ) O(n) O(n)

第三题

第三题换了个说法,但还是0-1背包问题,具体的描述记不太清楚了,就用0-1背包的变量设置直接上动态规划。
先写二维数组的解法:

def knapsack(C,value_list,weight_list):
    '''
              C : 背包容量
     value_list : 商品价值列表
    weight_list :商品重量列表
    
    '''
    n = len(value_list)
    dp = [[0 for i in range(C+1)] for j in range(n+1)]
    for i in range(1,n+1):
        for j in range(1,C+1):
            # 如果当前背包容量还够装下当前商品
            if j >= weight_list[i-1]:
                dp[i][j] = max(dp[i-1][j],dp[i-1][j-weight_list[i-1]]+value_list[i-1])
            else:
                dp[i][j] = dp[i-1][j]
    return dp[n][C]

性能分析:空间复杂度 O ( n 2 ) O(n^2) O(n2),时间复杂度 O ( n 2 ) O(n^2) O(n2)
得到dp矩阵后,可以回溯获取选择了哪些个商品,由dp矩阵的特性可知:

  • 若dp[i][j] = dp[i-1][j],说明没有选择第i个商品
  • 若dp[i][j] = dp[i-1][j-w[i-1]]+v[i-1],说明选择了第i个商品
def look_back(dp,value_list,weight_list):
    i = len(dp) - 1
    j = len(dp[0]) - 1
    res = []
    while (i>0):
        if dp[i][j] == dp[i-1][j]:
            i -= 1
        elif dp[i][j] == dp[i-1][j-weight_list[i-1]] + value_list[i-1]:
            res.append(i)
            j = j-weight_list[i-1]
            i -= 1
    return(res)

分析上述过程,其实dp可以使用1维矩阵来表示,从而降低空间复杂度。
在计算dp矩阵时,每次只使用上一行的数据,故每次计算时,除保存当前行数据外,再额外保存上一行数据即可。

def knapsack_ON(C,value_list,weight_list):
    '''
              C : 背包容量
     value_list : 商品价值列表
    weight_list :商品重量列表
    
    '''
    n = len(value_list)
    current_row = [0 for i in range(C+1)]
    last_row = [0 for i in range(C+1)]
    for i in range(1,n+1):
        for j in range(1,C+1):
            # 如果当前背包容量还够装下当前商品
            if j >= weight_list[i-1]:
                current_row[j] = max(last_row[j],last_row[j-weight_list[i-1]]+value_list[i-1])
            else:
                current_row[j] = last_row[j]
        # 此处注意不要直接用last_row = current_row,因为这样是浅复制
        last_row = [item for item in current_row] 
    return current_row[-1]

经验教训

  • 笔试的时候还是太急了,心态不够好,不冷静。
  • 要多考虑边界情况。
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值