动态编程:代码大战:两次线性:算法超时

时间:2018-03-19 10:38:11

标签: javascript algorithm performance dynamic-programming

我在代码大战中与卡塔挣扎: https://www.codewars.com/kata/5672682212c8ecf83e000050/train/javascript
我们的想法是创建一个数字序列,其中每个数字都是按照以下两个公式重新创建的:

y=2x + 1  
z=3x + 1  

x是序列中的当前数字。

从1开始,序列会像这样增长:

sequence = [1]  
x = 1  
y = 2*1 +1 = 3  
z = 3*1 + 1 = 4  
leading to sequence = [1, 3, 4]

将其应用于下一个数字会导致:

x = 3  
y = 2*3 + 1 = 7  
z = 3*3 + 1 = 10  
leading to sequence = [1, 3, 4, 7, 10]  

x = 4  
y = 2*4 + 1 = 9  
z = 3*4 + 1 = 13  
sequence [1, 3, 4, 7, 9, 10, 13]  

等等。请注意,我在最后一步中对序列进行了排序,因为x = 4(9和13)的结果必须与x = 3(7和10)的结果混合以保持有序序列。

[1,3,4,7,9,10,13,15,19,21,22,27,...]

我能够正确地解决问题,但实施应该是有效的,我正在超时。我的代码:

function dblLinear(n) {
  cache = {};
  cache[0] = 1;
  res = [1];
  lengthCounter = 0
  if (n === 0) {
    return 1;
  }
  for (var i = 1; i < n + 10; i++) {
    //console.log("i ", i)
    if (cache[i] === undefined && res.includes(i)) {
      //console.log('i: ', i, ' el1: ', i * 2 + 1, ' el2: ', i * 3 + 1);
      cache[i] = [i * 2 + 1, i * 3 + 1]
      if (!res.includes(i * 2 + 1)) {
        res.push(i * 2 + 1);
      }
      if (!res.includes(i * 3 + 1)) {
        res.push(i * 3 + 1);
      }
      //console.log("res ", res)
    }
    if (res.length !== lengthCounter) {
      var arrStart = res.slice(0, Math.floor(res.length / 2));
      var arrEnd = res.slice(Math.floor(res.length / 2), res.length)
      arrEnd.sort(function(a, b) {
        return a - b;
      });
      res = arrStart.concat(arrEnd)
      lengthCounter = res.length
    }
  }
  //console.log('res ', res);
  return res[n];
}

正如您在我的代码中所看到的,我尝试了一些简单的技巧来提高效率,但我猜测我需要更多的速度提升。您认为问题是什么?如何提高效率?

任何帮助将不胜感激!

干杯

曼努埃尔

3 个答案:

答案 0 :(得分:12)

这个问题可以在O(n)中解决。我们的想法是跟踪最后生成的元素并添加两种可能性中较小的一种,因此按顺序添加元素。这段代码很容易通过所有测试。

function dblLinear(n) {
    let u = [1], x = 0, y = 0
    for (let i = 0; i < n; i++) {
        let nextX = 2 * u[x] + 1, nextY = 3 * u[y] + 1
        if (nextX <= nextY) {
            u.push(nextX)
            x++
            if (nextX == nextY)
                y++
        } else {
            u.push(nextY)
            y++
        }
    }
    return u[n]
}

console.log(dblLinear(10) + " = " + 22)
console.log(dblLinear(20) + " = " + 57)
console.log(dblLinear(30) + " = " + 91)
console.log(dblLinear(50) + " = " + 175)
console.log(dblLinear(100) + " = " + 447)

答案 1 :(得分:3)

现有的解决方案很棒,但是我对这个问题的解决方案是

function dblLinear(n) {
  let eq1Index = 0;
  let eq2Index = 0;
  let eq1Array = [3];
  let eq2Array = [4];
  let result = 1;
  for (let i = 1; i <= n; i++) {
    if (eq1Array[eq1Index] < eq2Array[eq2Index]) {
      result = eq1Array[eq1Index];
      eq1Index++;
    } else {
      result = eq2Array[eq2Index];
      eq2Index++;
    }

    eq2Array.indexOf(2 * result + 1) == -1 && eq1Array.push(2 * result + 1);

    eq2Array.push(3 * result + 1);
  }
  return result;
}
console.log(dblLinear(10) + " = " + 22)
console.log(dblLinear(20) + " = " + 57)
console.log(dblLinear(30) + " = " + 91)
console.log(dblLinear(50) + " = " + 175)
console.log(dblLinear(100) + " = " + 447)

答案 2 :(得分:2)

一个好的解决方案

function dblLinear(n) {
  var ai = 0, bi = 0, eq = 0;
  var sequence = [1];
  while (ai + bi < n + eq) {
    var y = 2 * sequence[ai] + 1;
    var z = 3 * sequence[bi] + 1;
    if (y < z) { sequence.push(y); ai++; }
    else if (y > z) { sequence.push(z); bi++; }
    else { sequence.push(y); ai++; bi++; eq++; }
  }
  return sequence.pop();
}

console.log(dblLinear(10) + " = " + 22)
console.log(dblLinear(20) + " = " + 57)
console.log(dblLinear(30) + " = " + 91)
console.log(dblLinear(50) + " = " + 175)
console.log(dblLinear(100) + " = " + 447)