【问题标题】:Find the minimum cost combination algorithm求最小代价组合算法
【发布时间】:2022-01-25 16:43:35
【问题描述】:

给定一个包含至少 5 个项目的数组 N,我想找到 2 个数字(P 和 Q),其中 0

假设我们有以下数组:

const N = [1, 9, 4, 5, 8];
  • 如果 P = 1 , Q = 2 ,则成本将为 N[P] + N[Q] = N[1] + N[2] = 9 + 4 = 13
  • 如果 P = 1, Q = 3 ,则成本将为 N[P] + N[Q] = N[1] + N[3] = 9 + 5 = 14
  • 如果 P = 2, Q = 3 ,则成本将为 N[P] + N[Q] = N[2] + N[3] = 4 + 5 = 9

从这里得出最低成本的组合是P = 2Q = 3

这是我找到的解决方案,如果我能提高它的时间复杂度,我正在寻求您的帮助:

function solution(N) {
  // since  0 < P < Q < N - 1
  const sliced = N.slice(1, N.length - 1);
  const sorted = sliced.sort((a, b) => a - b);

  // the minimum should be from the start since we have sorted the array
  const P = 0;
  const Q = 1;

  return getCost(P, Q, sorted);
}

function getCost(P, Q, N) {
  return N[P] + N[Q];
}

// output should be 9
console.log(solution([1, 9, 4, 5, 8]))

在最好的情况下它是 0(n log(n)) 因为排序,但我想知道我们是否可以将其改进为 O(n)。

感谢您的帮助

【问题讨论】:

  • 你基本上需要的是数组中两个最小元素的总和? - 应该是O(N)。对于您的示例,不应该 P=0 和 Q=2 , sum = 5 而是解决方案吗?
  • @Jay 不,它是数组的子集中(第一个和最后一个元素应该排除)中两个最小元素的总和
  • 好的,在这种情况下,它将是N.slice(1, N.length - 1) 的两个最小数字的总和。您可以通过跟踪最小和第二小的编号来遍历数组一次。以及到目前为止看到的索引,这将是您的答案。
  • 您可以在 O(nlog(k)) 时间内找到数组中的 k 个最小元素。由于这里的 k=2,这是 O(n) 时间。快速选择或使用大小为 k 的堆是两种可能性。对于 k=2,您可以只保留两个变量并在遍历数组时更新它们。
  • @PaulHankin 正如我所说,应该排除第一个和最后一个元素

标签: javascript arrays algorithm performance time-complexity


【解决方案1】:
function twoSmallest(arr) {
  let [first, second] = [arr[1], arr[2]]
  
  for (let i = 3; i < arr.length - 1; i++) {
    const el = arr[i]
    if (el < first && el < second) {
      [first, second] = [Math.min(first, second), el] 
    } else if (el < first) {
      [first, second] = [second, el]
    } else if (el < second) {
      second = el
    }
  }
  return first + second
}

这是O(n) 时间和O(1) 空间解决方案。它还确保将具有较小索引的元素保留在first 中,以供您需要使用索引并且出于某种原因感兴趣的情况。

算法很清楚,IMO,但 JS 代码可能不是最好的实现。好久没写JS了。

【讨论】:

  • 非常感谢,这显然是 O(n),我们只需要一个循环,但我需要做一些调整,因为第一个应该小于第二个
  • 哦,对了。我认为first 应该是数组中second 之前的那个,意思是索引较小的那个。很高兴它有帮助。祝你有美好的一天:D @PetyIalimijoroRakotoniaina
  • 我相信这会对像[1,2,2,3,4] 这样的数组产生错误的答案,假设这些是可能的。此外,P 和 Q 不必是 P &lt; Q,只需 P != Q,因为解决方案是它们的总和。我相信它只是在问题中以这种方式描述的,因为从数学上来说更容易理解这个想法。
  • 测试了[1,2,2,3,4],它给了我4,这是正确的结果@Ouroborus。请解释您进一步看到的错误。谢谢。
  • 我的错误,我知道你现在如何避免这种情况了。
【解决方案2】:

你觉得这个解决方案怎么样?

function solution([_, ...n]) {
  n.pop()
  n.sort((a, b) => a - b);

  return n[0] + n[1];
}

// output should be 9
console.log(solution([1, 9, 4, 5, 8]))

逻辑与您概述的相同 - 仅使用 JS 提供的其他方法。

【讨论】:

  • @muka 但是因为排序还是 0(n log(n)) 对吧?
  • @PetyIalimijoroRakotoniaina 我认为 O 没有改变 - 只是实现更简洁。 (arguments.pop() 中的 spread 只是简化了 - 但逻辑是相同的)
  • 是的,肯定比我的解决方案更好
【解决方案3】:

我很确定这是 O(n):

const solution = (arr) => {
  // find smallest that's not at either end
  let idx = 1;
  let P = arr[1];
  for(let i = 2; i < arr.length-1; i++) {
    if(arr[i] < P) {
      idx = i;
      P = arr[i];
    }
  }
  // find second smallest that's not at either end
  let Q = Infinity;
  for(let i = 1; i < arr.length-1; i++) {
    if(i == idx) continue;
    if(arr[i] < Q) Q = arr[i];
  }
  return P + Q;
}

【讨论】:

    【解决方案4】:

    这是使用 Python 在列表中找到 k 个最小数字的最快方法。其余的都是微不足道的

    fastest method of getting k smallest numbers in unsorted list of size N in python?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-15
      • 2014-11-16
      • 1970-01-01
      相关资源
      最近更新 更多