我有一个数组和一个数字N。
数组可以用数字0,1,2,3 .... N
填充例如, arr = {1,0,2,3,1,0,2,4,3,1,0,2,4,3,0,0,0} //给定N = 4
我必须找到最小长度子阵列,其中包含所有数字1,2,... N。
例如,上面数组的答案应为{1,0,2,3,1,0, 2,4,3,1 ,0,2,4,3,0 ,0,0} // length = 4,索引为start = 6,end = 9,// 0 based
上述问题的一个可能答案是{1,0,2, 3,1,0,2,4 ,3,1,0,2,4,3,0,0, 0},但由于其长度为5,因此被拒绝.. 如果存在多于一个最小长度的子阵列,则应该是1次出现。 或者,如果数组在1,2..N之间不包含一个或多个数字,答案是“找不到子数组”。
这是我的python代码。它为某些情况(我不知道)产生了错误的答案...... 如果有人能说出我做错了什么。
shortlen=2000001 //initialise to INFINITY
shortstart=0
matchln=len(match) //match is the array containing integers
while(i<matchln):
if(match[i]>0):
leng=0
pos=[0]*n // array to keep status of found integers
j=i
start=i
sums=0
while(j<matchln and sums!=n):
if(match[j]>0):
if(pos[match[j]-1]==0): //only update status if the integer is not marked previously.
pos.pop(match[j]-1)
pos.insert(match[j]-1,1) //(match[j]-1) becuz array indexing is from 0.
sums+=1
j+=1
leng=j-i
if(j==matchln and sums!=n): // if the loop terminated,without marking all integers,that means we shouldn't proceed.
break
if(leng<shortlen): //if the length calculated is smaller then existing,then update it.
shortlen=leng
shortstart=start
i+=1
答案 0 :(得分:1)
一种可能性是跟踪每个起始位置的最短长度。您可以通过对数组进行两次传递来完成此操作:
假设索引1..k你在位置后找到了一组数字(在1..N内)(每个位置设置不同),当你前进到位置k + 1时,你需要更新全部使用位置k + 1处的数字设置(*)(只要数字在1..N内)。一旦集合包含N个元素,您就会找到该起始位置的最短序列,记录该位置的长度。
(*)意识到对于具有完整集的位置,您不再需要迭代它们。此外,一旦一个位置的集合已满,之前的位置集也必须是满的,因此您可以保持一个滑动的“起始位置”以检查集合
您现在可以执行另一次传递来为每个位置选择最短的记录序列(您可以根据开始和序列长度计算结束位置)。
status = new array[arr.length] of Status // for score keeping
// initialize Status with: set <- empty, length <- n+1
startPos = 1 // sliding start position
// first pass
for i = 1..arr.length
if arr[i] > 0 // within 1..N
for j = startPos..i
status[j].set.add(arr[i])
if status[j].set.size == N // we have all numbers
status[j].length = i-j;
startPos = j+1
min = n+1 // for the shortest length
startPos = 1
// second pass
for i = 1..status.length
if status[i].length < min
min = status[i].length
startPos = i
if min < n+1
// found a winner
print("start: " + startPos + ", end: " + startPos + min)
注意:上面代码中的索引从1开始(而不是从0开始)
答案 1 :(得分:0)
我想这可能会对你有所帮助。 您的问题的目标是将您的值转换为线性独立序列。我写了一个小代码来解决你的问题,它找到了你想要的序列的开头:
#include <stdio.h>
void main(){
/*By Volnei Klehm,
Manaus-AM, Brazil
2012
*/
long long arr[]={1,0,2,3,1,0,2,4,3,1,0,2,4,3,0,0,0};
long long power2arr[17]; /*same size or larger than arr*/
long long powerSum=0;
long long partialSum=0;
int count,count1,N;
int size_arr;
size_arr=sizeof(arr)/sizeof(long long);
/*the goal here is to find a way to represent your values as linear indepent ones,
here a sequece of power of 2 is used, you can also use other ways to do it that not increases so dramatically in values.
I use powers of 2 cause is more easy handled by computers, you can also use a sequence of sines,
cosines or any other math way that produces independets values.
For more informations I suggest you to take a look in linear algebra and/or digital signal processing books*/
/*Now it computes an independent basis*/
for(count=0 ; count<size_arr ; ++count){
power2arr[count] = 1 << arr[count]; /*calculates 2^arr generating a set of independent numbers.*/
}
N=4; /*put here your N, for n=4 it will look for*/
/*Notice that deppending on your system, N cannot be too large,
at certain point N values can make 2^N too large to be handled
by standard c/c++ types. Here is safe to use n up to 63.*/
/*now it gets the sum results of 2^0 + 2^1 + 2^2 ... + 2^N*/
++N; /* in C position starts at 0*/
for(count = 0 ; count < N ; count++)
powerSum |= 1 << count;
for(count = 0 ; count<size_arr ; ++count){
partialSum=0;
for(count1 = count ; count1 < (count + N) ; count1++){
if((count + N) > size_arr){
printf("No occurrences found!\n");
return;
}
partialSum |= power2arr[count1];
}
if(partialSum==powerSum){
printf("Ocurrence found at: %d\n", count);
return;
}
}
}
答案 2 :(得分:0)
如果允许额外的哈希表,可以一次完成。
基本上你在数组上保留两个指针: left 和 right ,两者都指向数组中的第一个元素。
在每一轮中,我们首先向前移动右侧。第一次移动后,只要 right 指向与 left 相同的值,我们也会向前移动 left 。我们当然会跳过0。
在每一轮中,我们维护哈希表以查看从1到N的哪个值在区间[left,right]内,如果所有值都在区间内,我们得到区间长度。我们在整个过程中跟踪最小间隔长度。
时间复杂度为O(Nn)