数组元素最大的连续子数组的数量

时间:2015-08-10 11:44:31

标签: algorithm

给定一个'n'整数数组,我需要找到数组的每个元素,将该元素作为其最大元素的连续子数组的数量。

元素可以重复。

有没有办法在少于O(n ^ 2)的情况下完成。

O(nlogn)还是O(n)?

Example-
If array is {1,2,3}. Then-
For '1': 1 Such subarray {1}.
For '2': 2 Such subarrays {2},{1,2}
For '3': 3 Such subarrays {3},{2,3},{1,2,3}

8 个答案:

答案 0 :(得分:3)

我很难用语言解释我的解决方案。我只想添加代码。它会解释自己:

#include <iostream>
#include <fstream>
using namespace std;

#define max 10000

int main(int argc, const char * argv[]) {

    ifstream input("/Users/appleuser/Documents/Developer/xcode projects/SubArrayCount/SubArrayCount/input.in");

    int n, arr[max], before[max]={0}, after[max]={0}, result[max];
    input >> n;
    for (int i=0; i<n; i++)
        input >> arr[i];

    for (int i=0;i<n;i++)
        for (int j=i-1;j>=0&&arr[j]<arr[i];j-=before[j]+1)
            before[i]+=before[j]+1;

    for (int i=n-1;i>=0;i--)
        for (int j=i+1;j<n&&arr[j]<arr[i];j+=after[j]+1)
            after[i]+=after[j]+1;

    for (int i=0;i<n;i++)
        result[i]= (before[i]+1)*(after[i]+1);

    for (int i=0; i<n; i++)
        cout << result [i] << " ";
    cout << endl;

    return 0;
}

解释(在[i] +1之前)*(在[i] +1之后):

对于我们需要的每个值,数字位于之前且小于该值,数字位于之后且小于该值。

  | 0  1  2  3  4  5 .... count of numbers less than the value and appears before.
---------------------
0 | 1  2  3  4  5  6
1 | 2  4  6  8  10 12
2 | 3  6  9  12 15 18
3 | 4  8  12 16 20 24
4 | 5  10 15 20 25 30
5 | 6  12 18 24 30 36
. | 
. |
. |
count of numbers less than the value and appears after.

示例:对于一个数字,其中有3个值小于它并且之前出现并且有4个值小于它并出现在之后。答案是V(3,4)= 20 =(3 + 1)*(4 + 1)

请告诉我结果。

您是否设法找到问题的来源链接?

答案 1 :(得分:2)

您可以将SubArrays大小存储在另一个数组(arr2)中,以避免重新计算它们。

arr2必须是arr1

中最大值的长度

即 -

获取数组{1,2,4,6,7,8}

arr2声明如下:

arr2 = []
for i in range(max(arr1)):
    arr2.append(0)

现在,算法是这样的:

说你打6号。

由于6-1=5不存在,因此0的默认值5对应于arr2中的索引0+1=1,因为尚未添加任何内容。因此,您将6存储在arr2的{​​{1}}位置。然后你输入数字7。您检查7-1=6中是否存在arr2。确实如此,其值为1。因此,将1+1=2的值添加到7中的arr2位置。

对于arr2中的每个值,我们只需将其添加到计数中。我们可以使用count变量同时执行此操作。

此算法为O(n)

答案 2 :(得分:1)

让我们看一个例子。

{4, 5, 6, 3, 2}

从开始到结束迭代,我们可以检测到单个增加的子阵列:{4, 5, 6}和两个单个元素32

因此我们检测子阵列3,1和1的长度。 第一个子阵列{4, 5, 6}给出了6个可能的决定,即1 + 2 + 3 = 6.它是一个关键。

对于任何长度增加的子阵列N,我们可以将决策数量计算为N * (N + 1)/2

因此我们有3 * (3 + 1)/2 + 1 * (1 + 1)/2 + 1 * (1 + 1)/2,即6 + 1 + 1 = 8

虽然我们只需要一次迭代,但我们有O(N)算法。

答案 3 :(得分:1)

您没有指定处理重复元素的方式/ 那个元素是什么(数组中精确位置的元素,或者数组中具有相同值的任何元素)。 假设问题是精确指数处的元素,这可以在线性时间内轻松解决:

define ctSubarrays(int[] in , int at)
    int minInd = at, maxInd = at;

    //search for the minimum-index (lowest index with a smaller element than in[at]
    for(; minInd > 0 && in[minInd - 1] < in[at] ; minInd--);

    //search for the maximum-index (highest index with a smaller element than in[at]
    for(; maxInd < length(at) - 1 && in[maxInd + 1] < in[at] ; maxInd++);

    //now we've got the length of the largest subarray meeting all constraints
    //next step: get the number of possible subarrays containing in[at]
    int spaceMin = at - minInd;
    int spaceMax = maxInd - at;

    return spaceMin * spaceMax;

答案 4 :(得分:1)

如果数组已排序,

count = 1;
for (i = 1 to n-1){
    if(a[i-1] == a[i]){
        count = count + 1;
    }else if(a[i-1] + 1 == a[i]){
        count of sub arrays for a[i-1] = count;
        count = count + 1;
    }else{
        count of sub arrays for a[i-1] = count;
        count = 1;
    }
}
count of sub arrays for a[n-1] = count;

如果数组未排序,

假设3:如果数组类似于{3,1,2,3},则3的#sub数组为3

aMin = min(a);//O(n)
aMax = max(a);
len = (aMax - aMin + 1);

create array b of size len;
for (j = 0 to len-1){
    b[j] = 0;
} 

count = 1;
for (i = 1 to n-1){
    if(a[i-1] == a[i]){
        count = count + 1;
    }else if(a[i-1] + 1 == a[i]){
        if(b[a[i-1] - aMin] < count){
            b[a[i-1] - aMin] = count;
        } 
        count = count + 1;
    }else{
        if(b[a[i-1] - aMin] < count){
            b[a[i-1] - aMin] = count;
        } 
        count = 1;
    }
}
if(b[a[n-1] - aMin] < count){
    b[a[n-1] - aMin] = count;
} 

for (i = 0 to n-1){
    count of sub arrays for a[i] = b[a[i] - aMin];
} 

即使数组包含负整数

,这也会有效

如果假设3根据您的问题失败,就像是,

假设4:如果数组类似于{3,1,2,3},则3的#sub数组为4

{3}, {1,2,3}, {2,3}, {3}

通过替换

修改上述代码
if(b[a[i-1] - aMin] < count){
    b[a[i-1] - aMin] = count;
} 

用这个

b[a[i-1] - aMin] = b[a[i-1] - aMin] + count; 

答案 5 :(得分:1)

创建一个value-to-index映射并从下到上遍历 - 维护一个增强的时间间隔树。每次添加索引时,请调整适当的间隔并计算相关段的总计。例如:

A = [5,1,7,2,3] => {1:1, 2:3, 3:4, 5:0, 7:2}

indexes     interval     total sub-arrays with maximum exactly
1           (1,1)        1 =>           1
1,3         (3,3)        2 =>           1 
1,3,4       (3,4)        3 =>           2
1,3,4,0     (0,1)        5 =>           2
1,3,4,0,2   (0,4)        7 => 3 + 2*3 = 9

augmented trees中的插入和删除时间复杂度为O(log n)。最坏情况的总时间复杂度为O(n log n)

答案 6 :(得分:0)

这是我使用Stack的O(N)时间Java解决方案。基本思路是从左向右跟踪以“ i”结尾的子数组,然后从右向左跟踪从“ i”开始的子数组:

public int[] countSubarrays(int[] arr) {
Stack<Integer> stack = new Stack<>();
int[] ans = new int[arr.length];
for(int i = 0; i < arr.length; i++) {
  while(!stack.isEmpty() && arr[stack.peek()] < arr[i]) {
    ans[i] += ans[stack.pop()];
  }
  stack.push(i);
  ans[i]++;
}
stack.clear();
int[] temp = new int[arr.length];
 for(int i = arr.length - 1; i >= 0; i--) {
  while(!stack.isEmpty() && arr[stack.peek()] < arr[i]) {
    int idx = stack.pop();
    ans[i] += temp[idx];
    temp[i] += temp[idx];
  }
  stack.push(i);
  temp[i]++;
}
return ans;

}

答案 7 :(得分:-1)

使用JavaScript 不确定Big O表示法。但是我在这里循环列表。然后开始2个循环。一个从i倒数,另一个从i + 1倒数。

let countArray = []
for(let i = 0; i < arr.length; i++){
  let count = 0;
  
  *This will count downwards starting at i*

  for(let j = i; j >= 0; j--){
    if(arr[j] > arr[i]) {break;}
    count++;
  }

  *This will count upwards starting at i+1 so that you dont get a duplicate of the first value*

  for(let j = i+1; j < arr.length; j++){
    if(arr[j] >= arr[i]) {break;}
    count++;
  }
countArray.push(count);
}
return countArray;