找到带分隔符的最大子阵列长度

时间:2018-01-03 02:20:02

标签: javascript algorithm

我试图解决这个问题:

给定两个参数:数组a和整数i,找到所有元素之和为<= i的最大数组长度。

例如,拥有以下数组:[3, 1, 2, 1]i = 4<= i的所有组合都是:[3], [1], [2], [3, 1], [1, 2], [1, 2, 1]。最大的子阵列是[1, 2, 1],因此函数的返回值应为3(数组长度)。

解决这个问题的有效方法是什么?

这是我的算法,直到现在,但我知道我错过了一些东西:

function sumArray(a) {
    return a.reduce((a, b) => a + b, 0)
}

function maxLength(a, i) {
   let max = 0
   let array = [a[0]]
   a.splice(1, a.length).forEach(number => {
     array.push(number)
     if (sumArray(array) <= k) max = array.length
     else array.splice(array.indexOf(Math.max.apply(null, array)), 1)
   })
   return max
}

3 个答案:

答案 0 :(得分:0)

蛮力方法可能是解决此问题的最佳方法。从每个条目开始,看看在到达总和select * from exchange where timestamp > "2018-01-02 17:30:00" AND timestamp < "2018-01-02 17:48:00"; 之前你可以走多远,如果它比你迄今为止看到的最好的那样保存它。我在下面提供了一个示例Java解决方案,我实际上并没有运行它,所以我的一个或两个索引可能会关闭,但我认为你可以获得要点。运行时间为O(n ^ 2),内存为O(n)(例如,都发生在#getMaxSubArray(new int [] {1,2,3,4,5,6,7,8,9,10] },1000000))

> i

答案 1 :(得分:0)

这是我将如何做到的。

首先,我们通过仅取出原始元素中的最小元素来获得最长的子阵列,因为这样,在我们进行时,总和将是最小的。所以:

&#13;
&#13;
const original = [3, 1, 2, 1];
const maxsum = 4;

// To make sure we take only the smallest, let's just
// sort the array straight away. That way the smallest
// element will always be the first.

// The .slice call is to make a copy, so we don't change
// the original:
const sorted = original.slice().sort();

// Here's your sum function. Looks legit.
function sumArray(a) {
    return a.reduce((a, b) => a + b, 0)
}

// Now take items from the front of the sorted array and
// put them in the new array until either the original is
// empty or the max is reached.
let subarray = [];
while (sorted.length) {
    // Get the next smallest element. It's always the
    // first one because of the sort.
    const smallest = sorted.shift();
    
    // If the sum of what we have plus this new element
    // is bigger than the max, our work is done:
    if (sumArray(subarray) + smallest > maxsum) break;
    
    // Otherwise, add it to our sub array and continue.
    subarray.push(smallest)
}

// Once that loop has run, either we ran out of elements,
// or we hit the max. Either way, our job is done.
console.log("Original array:", original);
console.log("Maximal subset:", subarray);
console.log("Maximal subset length:", subarray.length);
&#13;
&#13;
&#13;

最后,如果你想获得幻想,你甚至可以通过一次.reduce电话来做到这一点:

&#13;
&#13;
const original = [3, 1, 2, 1];
const maxsum = 4;

const maximalSubset = original.slice().sort().reduce((subset, current) => {
    if (subset.reduce((s, c) => s + c, 0) + current <= maxsum) subset.push(current);
    return subset;
}, []);

console.log("Orignal:", original);
console.log("Maximal subset:", maximalSubset);
console.log("Maximal subset length:", maximalSubset.length);
&#13;
&#13;
&#13;

虽然虽然较短,但第二个片段的缺点是我们必须在得到结果之前迭代整个数组,而第一个片段将在达到最大值后停止。

修改

事实证明,子阵列需要是原件的连续片段,所以改变原件的顺序不会起作用,因为我们需要确保结果是原件的连续切片。

要做到这一点,只需检查数组的每个子切片,并保持最佳状态:

&#13;
&#13;
let original = [74,659,931,273,545,879,924,710,441,166,493,43,988,504,328,730,841,613,304,170,710,158,561,934,100,279,817,336,98,827,513,268,811,634,980,150,580,822,968,673,394,337,486,746,229,92,195,358,2,154,709,945,669,491,125,197,531,904,723,667,550];
const maxsum = 22337;

function arraySum(arr) {
    return arr.reduce((p, c) => p + c, 0);
}

// Double for loop will do the trick.
let bestSoFar = [];
for (let i = 0; i < original.length; i++) {
    for (let j = i+1; j < original.length; j++) {
        if (j-i > bestSoFar.length && arraySum(original.slice(i, j)) < maxsum) {
            bestSoFar = original.slice(i, j);
        }
    }
}

console.log("Longest continuous subarray is:", bestSoFar.length);
&#13;
&#13;
&#13;

答案 2 :(得分:0)

这是我的解决方案。它将返回子数组的最大长度。你们可以看看吗?

function maxLength(a, k) {
const sortedArray = a.sort((i,j) => i - j);
let sum = 0;
let length = 0;
const subArray = [];
for (let i=0; i < sortedArray.length; i++) {
   sum = sum + sortedArray[i];
   if (sum <= k) {
      length++;
      subArray.push(sortedArray[i]);
   } else {
       return length;
   }
}
return length;
}