SoldierRanks-有什么方法可以减少时间复杂度?

时间:2019-12-26 15:07:54

标签: python time-complexity

我遇到了要解决的挑战:

  

在军队中,每个士兵都有一个指定的军衔。 X级士兵必须向X + 1级(任何)士兵报告。许多士兵可以向同一上级报告。

     

编写一个函数:   def solution(ranks): # write your code in Python 3.6 return len([i for i in ranks if i + 1 in ranks]) 在给定由士兵等级组成的数组等级的情况下,返回可以向上级报告的士兵人数。

     

示例:

     
      
  1. 给定等级= [3,4,3,0,2,2,2,3,0,0],您的函数应返回5,因为:

         
        
    • 三名三级士兵(等级[0],等级[2],等级[6])可以向四级士兵(等级[1])报告。
    •   
    • 两名2级士兵可以向任何3级士兵报告。
    •   
  2.   
  3. 给定等级= [4,2,0],您的函数应返回0。

  4.   
  5. 给定等级= [4,4,3,3,1,0],您的函数应返回3,因为:

         
        
    • 0级士兵可以向1级士兵报告。
    •   
    • 两名3级士兵可以向任何4级士兵报告。
    •   
  6.   
     

为以下假设写出有效的算法:

     
      
  • N是[2..100,000]范围内的整数;
  •   
  • 数组等级的每个元素都是[0..1,000,000,000]范围内的整数。
  •   

我提出了解决方案来解决它:

large_random
large random test
✘ TIMEOUT ERROR
running time: 3.196 sec., time limit: 0.528 sec.

large_sorted
large sorted array
✘ TIMEOUT ERROR
running time: 3.712 sec., time limit: 0.464 sec.

large_distinct
large distinct array
✘ TIMEOUT ERROR
Killed. Hard limit reached: 6.000 sec.

one_or_two_giant_pyramids
concatenated one or two dense (almost each K counts to the result) subarrays
✘ TIMEOUT ERROR
running time: 4.216 sec., time limit: 0.736 sec.

random_max_values
maximum size array containing maximum values
✘ TIMEOUT ERROR
Killed. Hard limit reached: 7.000 sec.

two_values_repeated
maximum size array with only two distinct values
✘ TIMEOUT ERROR
Killed. Hard limit reached: 7.000 sec.

此算法的复杂度为O(N²)。 我想知道是否有一种方法可以减少它并做出更快的算法,因为我为此得到了TIMEOUT_ERROR。

{{1}}

4 个答案:

答案 0 :(得分:3)

您可以通过计算最低级别(数字最高)的人数来找到不报告给其他人的士兵的数量,这可以在O(N)时间内完成;将其转换为要做的人数,在最坏的情况下将花费另一个O(N)时间(但可以在O(1)中完成)。

答案 1 :(得分:3)

首先将ranks设置为集合要快得多:

import timeit


r = [4, 2, 1, 3, 3, 2, 3, 5, 4] * 100

def solution1(ranks):
    return len([i for i in ranks if i+1 in ranks])

def solution2(ranks):
    rank_set = set(ranks)
    return len([i for i in ranks if i+1 in rank_set])

print(timeit.timeit(lambda: solution1(r), number=1000))
print(timeit.timeit(lambda: solution2(r), number=1000))

输出:

1.8472468510000002
0.13349082600000006

答案 2 :(得分:3)

另一种使用collections.Counter的解决方案(但是@ user10987432解决方案更干净-没有任何外部模块):

def solution_2(ranks):
    c = Counter(ranks)
    return sum(c[k] if k+1 in c else 0 for k in c)

基准:

from timeit import timeit
from collections import Counter

lst = [3, 4, 3, 0, 2, 2, 3, 0, 0] * 100

def solution_1(ranks):
    return len([i for i in ranks if i + 1 in ranks])

def solution_2(ranks):
    c = Counter(ranks)
    return sum(c[k] if k+1 in c else 0 for k in c)

def solution_3(ranks):
    rank_set = set(ranks)
    return len([i for i in ranks if i+1 in rank_set])


t1 = timeit(lambda: solution_1(lst), number=1000)
t2 = timeit(lambda: solution_2(lst), number=1000)
t3 = timeit(lambda: solution_3(lst), number=1000)

print(t1)
print(t2)
print(t3)

打印:

4.242018623999684
0.039016962999994576
0.05872536300012143

答案 3 :(得分:1)

根据我的评论,这是一个已实现的想法:

def solution(ranks):
    ranks.sort(key=lambda x: -x)
    is_group_ok = False
    result = 0
    for i in range(1, len(ranks)):
        if ranks[i] + 1 == ranks[i - 1]:
            result += 1
            is_group_ok = True
        elif ranks[i] == ranks[i - 1] and is_group_ok:
            result += 1
        else:
            is_group_ok = False
    return result

基于集合的解决方案将执行相同或更好的操作,但这是基于算法的解决方案(与使用set相对),这可能是可取的,也可能不是优选的。无论如何都要包括在内