华为2019校招编程题

题目简化后,召唤师能控制n种元素,并且将m个元素组合成一个新技能(这m个元素旋转或反转都算作一个,如123,132,312等),那么召唤师能组合多少技能,20000>=n>=1,10000>=m>=1,由于结果可能很大,请将结果对1000000007取余。

输入:3 3
输出:10
说明:111,112,113,122,123,133,222,223,233,333

代码一:

import sys
res = 0
def dfs(start,k,n,tmp):
    global res
    if k == 0:
        res = (res + 1) % 1000000007
        return
    for i in xrange(start,n+1):
        
        if not tmp or i >= tmp[-1]:
            tmp.append(i)
            dfs(i, k - 1, n, tmp)
            tmp.pop()

def combine(n,k):
    global res
    dfs(1,k,n,[])
    return res

n,k = 4,3
print combine(n,k)

可以发现,tmp仅记录合法序列,并比较最后一个,考虑用一个pre去代替tmp

优化1

import sys
res = 0
sys.setrecursionlimit(20001)
def dfs(start,k,n,pre):
    global res
    if k == 0:
        res = (res + 1) % 1000000007
        return
    for i in xrange(start,n+1):
        if not pre or i >= pre:
            dfs(i, k - 1, n, i)

def combine(n,k):
    global res
    # 注意传进去的pre为0
    dfs(1,k,n,0)
    return res

#n,k = 20000,10000
n,k = 4,3
print combine(n,k) 

进一步可以发现,pre和i的关系很大相关,

if not pre or i >= pre
	dfs(i, k - 1, n, i)

第一行主要保证下一层的递归,从pre-n+1去选择,但第二行传进去i作为pre,同i作为start,天然就能保证下一层递归的(start,n+1)循环中i >=pre,因此也可以去掉if判断。

优化2:

import sys
res = 0
sys.setrecursionlimit(20001)
def dfs(start,k,n):
    global res
    if k == 0:
        res = (res + 1) % 1000000007
        return
    for i in xrange(start,n+1):
        dfs(i, k - 1, n)

def combine(n,k):
    global res
    # 注意没有了参数pre
    dfs(1,k,n)
    return res

#n,k = 20000,10000
n,k = 4,3
print combine(n,k) 

该算法时间复杂度O(n),空间复杂度O(k),
但是如题中,当n,k = 20000,10000,耗时比较大,不一定能AC。

你可能感兴趣的:(算法分析)