如何有效地找到数字落入哪个范围?

时间:2019-03-06 02:12:52

标签: algorithm data-structures range

在求职面试中我被问到以下问题:

  

给出如下的分级所得税制度:

     
      
  • 最多10000税率为10%

  •   
  • 10001至50000的税率为20%

  •   
  • 50001及以上的税率为30%

  •   
     

编写一个程序以计算给定收入的税金。

     

示例:

     
      
  • 对15000征税是(5000的20%+ 10000的10%)= 2000

  •   
  • 60000的税将是(10000的30%+ 40000的20%+ 10000的10%)=   12000

  •   

我想出了以下伪代码:

list = (
    (1, 10000, 0.1)
    (10001, 50000, 0.2)
    (50001, infinity, 0.3)
)

taxableIncome = income
taxes = 0
while taxableIncome > 0
    find e in list such that taxableIncome is in range [e[1], e[2]]
    taxes += taxableIncome - e[1] + 1
    taxableIncome = e[1] - 1

return taxes

以上方法有效,但在最坏的情况下,列表中的项目数需要二次时间。考虑收入= 60000的情况;该代码将循环3次,每次都可能扫描整个列表。

有没有一种更快的方法来找出收入属于哪个范围? This问题提供了一些Python解决方案,但我对通用算法解决方案(而不是库)感兴趣。

2 个答案:

答案 0 :(得分:4)

预先计算每个范围开始处的税值,并将其包含在列表中。

我也删除了狄龙·戴维斯(Dillon Davis)在注释中注意到的上限,并将下限值更改为先前范围的末尾以使公式更精确

 list = (
        (0, 0, 0.1)
        (10000, 1000, 0.2)
        (50000, 9000, 0.3)
    )

对于给定的收入,通过线性搜索(如果范围的数量很小)或通过二元搜索(如果范围很多-几十个,数百个等等)找到合适的范围

然后只需使用简单的公式计算税款

  tax  = e[2] + (income - e[1]) * e[3]

enter image description here

对于收入15000,我们可以找到

range = 2nd interval (10000, 1000, 0.2)
tax = 1000 + (15000 - 10000) * 0.2 = 
      1000 + 5000 * 0.2 = 2000

或者(使用Dillon Davis的建议)

  tax  = income * e[3] + (e[2] -  e[1]) * e[3])
  tax  = income * e[3] + e[2]'

具有针对每个范围的预先计算的e2' = (e[2] - e[1]) * e[3])

总体复杂度为线性或对数(带BS)

答案 1 :(得分:0)

这里的OP:@MBo的答案让我开始思考(为此表示支持),但不幸的是,他没有以对我足够清楚的方式对其进行解释,所以我们开始吧。

import logging TRACE = 45 def trace(self, msg, *args, **kwargs): return self.log(TRACE, msg, *args, **kwargs) logging.LoggerAdapter.trace = trace logger = logging.getLogger(__file__) adapter = logging.LoggerAdapter(logger, {'some': 'info'}) adapter.trace('trace') 为括号的数量。

简单的方法::线性搜索适当的税级,对税级中的超额收入征税,然后递归地对税级中的应税收入征税。例如,收入N放在以15000开头的括号中;该括号的税是10001 + (15000 - 10000) * 0.2 = 1000的税。 此方法可行,但在最坏的情况下,如果初始收入降到最高,则线性搜索可能需要10000 括号,代码将循环N次。我们最终得到了O(N ^ 2)算法。

更好的方法:二进制搜索方括号,然后按照幼稚的方法进行操作。 O(N)

动态编程方法::此问题同时显示了应用动态编程的两个标准, 最佳子结构和重叠子问题。为什么?每个等级的总税额是当前等级的税额与剩余应纳税所得额的税额之和。对于每个括号,递归解决方案会一遍又一遍地计算下一个括号的税额。

因此,我们以自下而上的方式预先计算并记录了应税收入的税款,直到上一桶。 这需要O(N log(N))时间。对括号进行二进制搜索需要O(N)时间。现在,计算税款需要log(N)倍,从而使我们总体上有了一个线性时间算法。

Scala代码:随时适应您喜欢的编程语言。

O(1)

def taxes(income: Int, brackets: IndexedSeq[(Int, Double)]): Double = { val dp = brackets .zipWithIndex .foldLeft((0d, IndexedSeq.empty[(Int, Double, Double)])) { case ((sum, acc), (cur, i)) => val taxesOnPrevBracket = if (i > 0) { val prev = brackets(i - 1) (cur._1 - prev._1) * prev._2 } else 0d val cumulativeTaxes = sum + taxesOnPrevBracket (cumulativeTaxes, acc :+ (cur._1, cur._2, cumulativeTaxes)) } ._2 @tailrec def findBracket(start: Int, end: Int): Int = { if (end - start <= 1) start else { val mid = start + (end - start) / 2 if (income > brackets(mid)._1) findBracket(mid, end) else findBracket(start, mid) } } val br = dp(findBracket(0, brackets.size - 1)) val inc = income - br._1 + 1 val tx = inc * br._2 + br._3 println(s"Taxable income: $income, bracket: $br, taxes: $tx") tx } 是一个元组序列,包含初始值(感谢@Dillon Davis的想法)和税率。