Codility Peak JavaScript实现

时间:2017-08-23 03:40:16

标签: javascript algorithm puzzle

我正在研究Codility Peak problem

  

将数组划分为相同大小的块的最大数量,每个块应包含索引 P ,使得 A [P-1]< A [P]> A [P + 1]

我自己的解决方案如下,但只有45%。所以我的问题是:

我怎样才能改进我的解决方案?

代码片段似乎很长,因为我添加了一些额外的注释以使自己更清楚:

function solution(A) {
  var storage = [], counter = 0;
  // 1. So first I used a loop to find all the peaks
  // and stored them all into an array called storage
  for(var i = 1; i < A.length - 1; i++) {
    if (A[i] > A[i-1] && A[i] > A[i+1]) {
        storage.push(i);
    }
  }
  // 2. Go and write the function canBeSeparatedInto
  // 3. Use the for loop to check the counter
  for(var j = 1; j < A.length; j++) {
    if (canBeSeparatedInto(j, A, storage)) {
      counter = j;
    }
  }
  return counter;
}

/* this function tells if it is possible to divide the given array into given parts
 * we will be passing our function with parameters: 
 * @param parts[number]: number of parts that we intend to divide the array into
 * @param array[array]: the original array
 * @param peaks[array]: an storage array that store all the index of the peaks
 * @return [boolean]: true if the given array can be divided into given parts
 */
function canBeSeparatedInto(parts, array, peaks) {
    var i = 1, result = false;
    var blockSize = array.length / parts;
    peaks.forEach(function(elem) {
    // test to see if there is an element in the array belongs to the ith part
        if ((elem+1)/blockSize <= i && (elem+1)/blockSize> i-1) {
            i++;
        }
    });
    // set the result to true if there are indeed peaks for every parts
    if (i > parts) {
        result = true;
    }
    return result;
}

我的代码的主要问题是它没有通过性能测试。你能给我一些暗示吗?

2 个答案:

答案 0 :(得分:1)

我会建议这个算法:

  • 按照他们与前任的距离对偷看进行排序。要做到这一点,可能更直观地识别&#34;山谷&#34;,即没有偷看的最大范围,并按其大小按降序排序

  • 确定数组长度的除数,因为解决方案必须是其中之一。例如,当数组长度为素数时,测试解决方案是浪费时间:在这种情况下,答案只能为1(如果没有窥视则为零)。

  • 按升序尝试每个除数(表示数组块的大小),看看对于每个山谷这样的分裂是否会将其中一个块完全带入该山谷内,即它不会包含窥视:在这种情况下,拒绝该大小作为解决方案,并尝试下一个大小。

使用数组的交互式输入实现:

&#13;
&#13;
"use strict";
// Helper function to collect the integer divisors of a given n
function divisors(n) {
    var factors = [], 
        factors2 = [],
        sq = Math.sqrt(n);
    for (var i = 1; i <= sq; i++) {
        if (n % i === 0) {
            factors.push(n / i);
            // Save time by storing complementary factor as well
            factors2.push(i);
        }
    }
    // Eliminate possible duplicate when n is a square
    if (factors[factors.length-1] === factors2[factors2.length-1]) factors.pop();
    // Return them sorted in descending order, so smallest is at end
    return factors.concat(factors2.reverse());
}

function solution(A) {
    var valleys = [],
        start = 0,
        size, sizes, i;
    // Collect the maximum ranges that have no peeks
    for (i = 1; i < A.length - 1; i++) {
        if (A[i] > A[i-1] && A[i] > A[i+1]) {
            valleys.push({
                start,
                end: i,
                size: i - start,
            });
            start = i + 1;
        }
    }
    // Add final valley
    valleys.push({
        start,
        end: A.length,
        size: A.length - start 
    });
    if (valleys.length === 1) return 0; // no peeks = no solution
    // Sort the valleys by descending size 
    // to improve the rest of the algorithm's performance
    valleys.sort( (a, b) => b.size - a.size );
    // Collect factors of n, as all chunks must have same, integer size
    sizes = divisors(A.length)
    // For each valley, require that a solution must not 
    // generate a chunk that falls completely inside it
    do {
        size = sizes.pop(); // attempted solution (starting with small size)
        for (i = 0;
            i < valleys.length &&
            // chunk must not fit entirely inside this valley
            Math.ceil(valleys[i].start / size) * size + size > valleys[i].end; i++) {
        }
    } while (i < valleys.length); // keep going until all valleys pass the test
    // Return the number of chunks
    return A.length / size;
}

// Helper function: chops up a given array into an  
//   array of sub arrays, which all have given size, 
//   except maybe last one, which could be smaller.
function chunk(arr, size) {
    var chunks = [];
    for (var i = 0; i < arr.length; i += size) {
        chunks.push(arr.slice(i, i + size));
    }
    return chunks;
}

// I/O management
inp.oninput = function () {
    // Get input as an array of positive integers (ignore non-digits)
    if (!this.value) return;
    var arr = this.value.match(/\d+/g).map(v => +v);
    var parts = solution(arr);
    // Output the array, chopped up into its parts:
    outCount.textContent = parts;
    outChunks.textContent = chunk(arr, arr.length / parts).join('\n');
}
&#13;
Array (positive integers, any separator): <input id="inp" style="width:100%">
Chunks: <span id="outCount"></span>
<pre id="outChunks"></pre>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

当检查数组是否可以分成K个部分时,在最坏的情况下([1,2,1,2,1,...]的数组)会进行N / 2个检查(因为你正在查看每个峰)。

这可以通过使用聪明的数据结构以K步骤完成: 将峰表示为二进制数组(0 - 无峰,1 - 峰)。计算前缀总和。如果要检查块是否包含峰值,只需比较块的开头和结尾的前缀和。

而且你还有其他小问题。你不应该检查不分割数组大小的块数。