You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Code Wars Twice Linear问题:动态规划解法超时求助

解决数列生成超时问题的优化思路

嘿,我碰到过类似的问题,这个数列的生成逻辑和经典的丑数问题高度相似,你用动态规划出现超时,大概率是因为没有避免重复计算或者遍历方式不够高效。下面给你两个靠谱的优化方案:

方案一:双指针法(最优,O(n)时间复杂度)

这个思路的核心是:数列中的每个数都是由前面的数通过2x+1或3x+1生成的,我们可以用两个指针分别跟踪这两种生成方式的候选位置,每次选择较小的候选值加入数列,同时移动对应的指针(如果两个候选值相等,两个指针都移动,避免重复)。

示例代码(JavaScript)

function generateSequence(n) {
  const sequence = [1];
  let pointer2 = 0, pointer3 = 0;

  for (let i = 1; i < n; i++) {
    const nextFrom2 = 2 * sequence[pointer2] + 1;
    const nextFrom3 = 3 * sequence[pointer3] + 1;
    const nextValue = Math.min(nextFrom2, nextFrom3);

    sequence.push(nextValue);
    // 移动对应指针,若两个值相等则同时移动,避免重复添加
    if (nextValue === nextFrom2) pointer2++;
    if (nextValue === nextFrom3) pointer3++;
  }

  return sequence;
}

为什么高效?

每个指针只会单向向前移动,不会回头,整个过程是线性遍历,没有重复计算,也不需要额外的空间存储候选值(除了结果数组),完全不会出现超时问题。

方案二:最小堆(优先队列),O(n logn)时间复杂度

如果双指针的逻辑一时不好理解,用最小堆也是个不错的选择。我们用堆来维护所有候选的下一个数,每次弹出堆顶的最小值(保证数列有序),然后生成对应的2x+1和3x+1,用集合去重后加入堆中。

示例代码(JavaScript)

class MinHeap {
  constructor() {
    this.heap = [];
  }

  push(val) {
    this.heap.push(val);
    this.bubbleUp(this.heap.length - 1);
  }

  pop() {
    const min = this.heap[0];
    const end = this.heap.pop();
    if (this.heap.length > 0) {
      this.heap[0] = end;
      this.sinkDown(0);
    }
    return min;
  }

  bubbleUp(idx) {
    const val = this.heap[idx];
    while (idx > 0) {
      const parentIdx = Math.floor((idx - 1) / 2);
      const parent = this.heap[parentIdx];
      if (val >= parent) break;
      this.heap[idx] = parent;
      this.heap[parentIdx] = val;
      idx = parentIdx;
    }
  }

  sinkDown(idx) {
    const length = this.heap.length;
    const val = this.heap[idx];
    while (true) {
      let leftChildIdx = 2 * idx + 1;
      let rightChildIdx = 2 * idx + 2;
      let swapIdx = null;

      if (leftChildIdx < length && this.heap[leftChildIdx] < val) {
        swapIdx = leftChildIdx;
      }
      if (rightChildIdx < length) {
        const rightChild = this.heap[rightChildIdx];
        if ((swapIdx === null && rightChild < val) || (swapIdx !== null && rightChild < this.heap[swapIdx])) {
          swapIdx = rightChildIdx;
        }
      }
      if (swapIdx === null) break;
      this.heap[idx] = this.heap[swapIdx];
      this.heap[swapIdx] = val;
      idx = swapIdx;
    }
  }
}

function generateSequence(n) {
  const heap = new MinHeap();
  const seen = new Set();
  const sequence = [];

  heap.push(1);
  seen.add(1);

  for (let i = 0; i < n; i++) {
    const current = heap.pop();
    sequence.push(current);

    const next2 = 2 * current + 1;
    if (!seen.has(next2)) {
      seen.add(next2);
      heap.push(next2);
    }

    const next3 = 3 * current + 1;
    if (!seen.has(next3)) {
      seen.add(next3);
      heap.push(next3);
    }
  }

  return sequence;
}

为什么能解决超时?

堆的弹出和插入操作是O(logk)(k为堆的大小),加上去重的集合操作,整体时间复杂度是O(n logn),对于大部分场景来说效率足够,不会出现超时。


内容的提问来源于stack exchange,提问作者user9515918

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:15:02