给定一个'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}
答案 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}
和两个单个元素3
和2
。
因此我们检测子阵列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;