【问题标题】:Index of users distributed across rooms分布在房间内的用户索引
【发布时间】:2020-09-21 11:25:34
【问题描述】:

我是 stackoverflow 的新手,所以如果我解释不当,请指导我。

我有一个长度为 N 的整数集合(Array[Int]),其中某个索引 i 处的每个元素表示房间 Ri 中存在的用户数。在Ri房间中,用户也被索引,第一个房间的用户索引从1R1,第二个房间包含R1 + 1 to R1 + R2等等。

现在输入是用户的索引,我需要找出用户在哪个房间。

我的解决方案是这样的:

def getRoomNumber(userIndex: Int, userDistribution: Array[Int]): Int = {

    val cummulativeRooms: Array[Int] = 
        rooms.tail.scanLeft(rooms.head)((x, y) => x + y)

    val roomIndex = cummulativeRooms.takeWhile(_ < userIndex).length + 1

    roomIndex
}

这里,因为用户 4 将出现在房间 2 中(因为房间有这样的用户分布:Room1(U1, U2)Room2(U3, U4, U5))。

我的代码在这个输入上运行良好。但是我有一些隐藏的测试用例,其中一半通过了。但是后半部分没有,有的甚至抛出异常。

谁能告诉我我的代码有什么问题。还有比这更有效的算法吗?

更多解释-

假设我有 10 个用户 - U1、U2、U3、U4、U5,我们按照 userDistribution 数组 - Array(2, 3) 定义的顺序将它们分成 N 个房间。这意味着用户 U1 和 U2 将出现在房间 1 中,而从 U3 到 U5 的用户将出现在房间 2 中。

现在,如果我想找出用户 U4 在哪里,那么输出应该是 2。输入是用户索引,在这种情况下是 4,userDistribution array - Array(2, 3)

编辑:代码更改为函数。输入是我们要查找的用户索引和userDistributions,其中包含按顺序出现在每个房间中的用户数量。

编辑:约束是(我们不必在代码中检查这些约束) - N 和 Ui 的值都可以在 1 到 10e5 之间。 此外,Ui 将小于数组的总和。

【问题讨论】:

  • 欢迎来到 StackOverflow,Harry。有点不清楚您期望产生的输出是什么。也许您可以定义一个函数来阐明您拥有哪些输入以及您期望的输出是什么。运行时期望的类型和一点解释(可能带有一些测试用例)可以帮助您轻松获得相关答案。干杯!
  • @stefanobaghino 感谢您的建议。我现在已经把我的代码变成了一个函数。我希望现在会更清楚。此外,测试用例以及例外情况都是隐藏的,这就是我自己无法解决的原因。我的代码有什么问题对我来说并不明显。
  • @stefanobaghino 如果你有不同的方法来解决这个问题,我也很乐意看到。
  • getRoomNumber(10000, Array(1)) 的预期输出是什么?
  • 了解其他边缘情况也会很有趣(用户索引不足/溢出、空数组、处理房间之间的“边缘”时的行为等)

标签: scala optimization sequence


【解决方案1】:

如果我对问题的理解正确,您只需要迭代用户的分布数组并保留您所见过的用户数量的总和,直到该总和大于或等于目标用户。

您可以使用命令式解决方案轻松做到这一点:

// Return Option because we can not guarantee the constraints.
// Also, ArraySeq is just an immutable array.
def imperativeSolution(userDistribution: ArraySeq[PositiveInt])(targetUser: PositiveInt): Option[PositiveInt] = {
  var acc = 0
  for (i <- userDistribution.indices) {
    acc += userDistribution(i)
    if (targetUser <= acc) return Some(i + 1)
  }
  None
}

但是,由于return 的可变性和使用,这是相当“丑陋”
我们可能宁愿使用递归方法:

// It is better to use a recursive data structure like List for a recursive algorithm.
def recursiveSolution(userDistribution: List[PositiveInt])(targetUser: PositiveInt): Option[PositiveInt] = {
  @annotation.tailrec
  def loop(remaining: List[PositiveInt], idx: PositiveInt, acc: PositiveInt): Option[PositiveInt] =
    remaining match {
      case x :: xs =>
        val newAcc = acc + x
        if (targetUser <= newAcc) Some(idx)
        else loop(remaining = xs, idx + 1, newAcc)
      
      case Nil =>
        None
    }
  
  loop(remaining = userDistribution, idx = 1, acc = 0)
}

这是不可变的,但它有很多样板,我们可以使用更功能性的解决方案来减少这些样板并使其更具表现力:

def functionalSolution(userDistribution: IterableOnce[PositiveInt])(targetUser: PositiveInt): Option[PositiveInt] =
  userDistribution
    .iterator
    .scanLeft(0)(_ + _)
    .zipWithIndex
    .collectFirst {
      case (acc, idx) if (targetUser <= acc) => idx
    }

你可以看到他们在运行here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多