Arrays 寻找最大平衡子阵的空间有效算法?
给定一个0和1的数组,找到最大子数组,使0和1的数量相等。 这需要在O(n)时间和O(1)空间中完成 我有一个算法,它在O(n)时间和O(n)空间中完成。它使用一个前缀和数组,并利用这样一个事实:如果0和1的数量相同,那么 sumOfSubarray=长度ThofSubarray/2Arrays 寻找最大平衡子阵的空间有效算法?,arrays,algorithm,binary-data,Arrays,Algorithm,Binary Data,给定一个0和1的数组,找到最大子数组,使0和1的数量相等。 这需要在O(n)时间和O(1)空间中完成 我有一个算法,它在O(n)时间和O(n)空间中完成。它使用一个前缀和数组,并利用这样一个事实:如果0和1的数量相同,那么 sumOfSubarray=长度ThofSubarray/2 #include<iostream> #define M 15 using namespace std; void getSum(int arr[],int prefixsum[],int size
#include<iostream>
#define M 15
using namespace std;
void getSum(int arr[],int prefixsum[],int size) {
int i;
prefixsum[0]=arr[0]=0;
prefixsum[1]=arr[1];
for (i=2;i<=size;i++) {
prefixsum[i]=prefixsum[i-1]+arr[i];
}
}
void find(int a[],int &start,int &end) {
while(start < end) {
int mid = (start +end )/2;
if((end-start+1) == 2 * (a[end] - a[start-1]))
break;
if((end-start+1) > 2 * (a[end] - a[start-1])) {
if(a[start]==0 && a[end]==1)
start++; else
end--;
} else {
if(a[start]==1 && a[end]==0)
start++; else
end--;
}
}
}
int main() {
int size,arr[M],ps[M],start=1,end,width;
;
cin>>size;
arr[0]=0;
end=size;
for (int i=1;i<=size;i++)
cin>>arr[i];
getSum(arr,ps,size);
find(ps,start,end);
if(start!=end)
cout<<(start-1)<<" "<<(end-1)<<endl; else cout<<"No soln\n";
return 0;
}
#包括
#定义M 15
使用名称空间std;
void getSum(int arr[],int prefixsum[],int size){
int i;
前缀sum[0]=arr[0]=0;
前缀sum[1]=arr[1];
对于(i=2;i2*(a[end]-a[start-1])){
如果(a[start]==0&&a[end]==1)
开始++;否则
结束--;
}否则{
如果(a[start]==1&&a[end]==0)
开始++;否则
结束--;
}
}
}
int main(){
整数大小,arr[M],ps[M],开始=1,结束,宽度;
;
cin>>尺寸;
arr[0]=0;
结束=大小;
对于(int i=1;i>arr[i];
getSum(arr、ps、size);
查找(ps、开始、结束);
如果(开始!=结束)
cout对数组中的所有元素求和,那么diff=(array.length-Sum)将是0和1的数量之差
如果diff等于array.length/2,则最大子阵列=阵列
如果差异小于array.length/2,则1多于0
如果差异大于array.length/2,则0多于1
对于案例2和3,初始化两个指针,开始和结束指向数组的开始和结束。如果有更多的1,则根据数组[start]=1或数组[end]=1向内移动指针(开始++或结束--),并相应地更新sum。在每一步检查sum=(结束-开始)/2.如果此条件为真,则开始和结束表示最大子阵列的边界
在这里,我们对数组进行了两次遍历,一次用于计算和,一次用于向内移动指针。我们使用常量空间,因为我们只需要存储和和和两个索引值
如果有人想编造一些伪代码,你是非常受欢迎的:)不同的方法,但仍然是O(n)时间和内存。从Neil的建议开始,将0视为-1
表示法:A[0,…,N-1]
-您的大小数组N
,f(0)=0,f(x)=A[x-1]+f(x-1)
-函数
如果你绘制f
,你会看到,你要寻找的是f(m)=f(n),m=n-2k
的点,其中k为正自然。更准确地说,只有x
这样A[x]!=A[x+1]
(以及数组中的最后一个元素)你必须检查f(x)
已经发生。不幸的是,现在我看不到比使用数组B[-N+1…N-1]
存储这些信息的地方有什么改进
为了完成我的想法:B[x]=-1
最初,B[x]=p
当p=mink:f(k)=x
时,算法是(仔细检查,因为我很累):
检查具有某个给定长度L的“求和为零属性”的子阵列很简单:
a = 0
b = L
fa = fb = 0
for i=0…L-1:
fb = fb + A[i]
while (fa != fb) and (b<N) :
fa = fa + A[a]
fb = fb + A[b]
a = a + 1
b = b + 1
if b==N:
not found
found, starts at a and stops at b
a=0
b=L
fa=fb=0
对于i=0…L-1:
fb=fb+A[i]
而(fa!=fb)和(b现在我的算法是O(n)时间和O(Dn)空间,其中Dn是列表中的总不平衡。
此解决方案不会修改列表
设D为列表中1和0的差值
首先,让我们线性地遍历列表并计算D,看看它是如何工作的:
我将以这个列表为例:l=1100111100001110
Element D
null 0
1 1
1 2 <-
0 1
0 0
1 1
1 2
1 3
1 4
0 3
0 2
0 1
0 0
1 1
1 2
1 3
0 2 <-
您选择了差异最大的元素:2:(2,15)并且是l[3:15]=00111100001110(l=1100111100001110)
时间复杂性:
2个过程,第一个用于计算Dn,第二个用于构建
措辞。
在字典里找到最大值
总数为0(n)
空间复杂性:
D:O(1)中的当前元素是词汇表O(Dn)
我不会因为这句话而把3和4放在毕业典礼上
<> P> <强>复杂度为O(n)时间和O(DN)空间(在平均情况下,Dn席胡>尼尔),我认为考虑字母{±1 }而不是{ 0, 1 }是有用的。假设不丢失一般性,至少有+1s为-1s。下面的算法使用“强> O(qRT(n log n))< /强>位,并在时间O(n)中运行,这是由于“AF”。
注意:此解决方案不会通过假设输入可修改和/或浪费位来欺骗。截至此次编辑,此解决方案是唯一一个同时为O(n)时间和O(n)空间的发布方案
一个更简单的版本使用O(n)位,对前缀和数组进行流式处理,并标记每个值的第一次出现。然后向后扫描,考虑0和sum(arr)之间的每个高度,该高度的最大子数组。一些想法表明,最佳值是其中之一(记住假设)。在Python中:
sum = 0
min_so_far = 0
max_so_far = 0
is_first = [True] * (1 + len(arr))
for i, x in enumerate(arr):
sum += x
if sum < min_so_far:
min_so_far = sum
elif sum > max_so_far:
max_so_far = sum
else:
is_first[1 + i] = False
sum_i = 0
i = 0
while sum_i != sum:
sum_i += arr[i]
i += 1
sum_j = sum
j = len(arr)
longest = j - i
for h in xrange(sum - 1, -1, -1):
while sum_i != h or not is_first[i]:
i -= 1
sum_i -= arr[i]
while sum_j != h:
j -= 1
sum_j -= arr[j]
longest = max(longest, j - i)
sum=0
min_so_far=0
到目前为止的最大值=0
is_first=[True]*(1+len(arr))
对于枚举(arr)中的i,x:
总和+=x
如果迄今为止总和小于最小值:
min_so_far=总和
elif sum>max_至今:
最大迄今为止=总和
其他:
是_first[1+i]=False
和i=0
i=0
而sum_i!=sum:
总和i+=arr[i]
i+=1
sum_j=sum
j=长(arr)
最长=j-i
对于X范围内的h(和-1,-1,-1):
当sum_i!=h是否为_first[i]:
i-=1
总和i-=arr[i]
当sum_j!=h时:
j-=1
sum_j-=arr[j]
最长=最大值(最长,j-i)
降低空间的诀窍在于注意到我们正在按顺序扫描is_first
,尽管顺序与其构造相反。由于循环变量适合于O(logn)位,我们将在每个O之后计算循环变量的检查点,而不是is_first
(√(n日志n)步骤。这是O(n/√(n对数n))=O(√(n/log n))检查点,共有0个(√(n log n))位由r
Element D
null 0
1 1
1 2 <-
0 1
0 0
1 1
1 2
1 3
1 4
0 3
0 2
0 1
0 0
1 1
1 2
1 3
0 2 <-
Element D DICTIONNARY
null 0 {0:(0,0)}
1 1 {0:(0,0) 1:(1,1)}
1 2 {0:(0,0) 1:(1,1) 2:(2,2)}
0 1 {0:(0,0) 1:(1,3) 2:(2,2)}
0 0 {0:(0,4) 1:(1,3) 2:(2,2)}
1 1 {0:(0,4) 1:(1,5) 2:(2,2)}
1 2 {0:(0,4) 1:(1,5) 2:(2,6)}
1 3 { 0:(0,4) 1:(1,5) 2:(2,6)}
1 4 {0:(0,4) 1:(1,5) 2:(2,6)}
0 3{0:(0,4) 1:(1,5) 2:(2,6) }
0 2 {0:(0,4) 1:(1,5) 2:(2,9) }
0 1 {0:(0,4) 1:(1,10) 2:(2,9) }
0 0 {0:(0,11) 1:(1,10) 2:(2,9) }
1 1 {0:(0,11) 1:(1,12) 2:(2,9) }
1 2 {0:(0,11) 1:(1,12) 2:(2,13)}
1 3 {0:(0,11) 1:(1,12) 2:(2,13)}
0 2 {0:(0,11) 1:(1,12) 2:(2,15)}
sum = 0
min_so_far = 0
max_so_far = 0
is_first = [True] * (1 + len(arr))
for i, x in enumerate(arr):
sum += x
if sum < min_so_far:
min_so_far = sum
elif sum > max_so_far:
max_so_far = sum
else:
is_first[1 + i] = False
sum_i = 0
i = 0
while sum_i != sum:
sum_i += arr[i]
i += 1
sum_j = sum
j = len(arr)
longest = j - i
for h in xrange(sum - 1, -1, -1):
while sum_i != h or not is_first[i]:
i -= 1
sum_i -= arr[i]
while sum_j != h:
j -= 1
sum_j -= arr[j]
longest = max(longest, j - i)
protected function findLongest(array:Array, start:int = 0, end:int = -1):int {
if (end < start) {
end = array.length-1;
}
var startDiff:int = 0;
var endDiff:int = 0;
var diff:int = 0;
var length:int = end-start;
for (var i:int = 0; i <= length; i++) {
if (array[i+start] == '1') {
startDiff++;
} else {
startDiff--;
}
if (array[end-i] == '1') {
endDiff++;
} else {
endDiff--;
}
//We can stop when there's no chance of equalizing anymore.
if (Math.abs(startDiff) > length - i) {
diff = endDiff;
start = end - i;
break;
} else if (Math.abs(endDiff) > length - i) {
diff = startDiff;
end = i+start;
break;
}
}
var bit:String = diff > 0 ? '1': '0';
var diffAdjustment:int = diff > 0 ? -1: 1;
//Strip off the bad vars off the ends.
while (diff != 0 && array[start] == bit) {
start++;
diff += diffAdjustment;
}
while(diff != 0 && array[end] == bit) {
end--;
diff += diffAdjustment;
}
//If we have equalized end. Otherwise recurse within the sub-array.
if (diff == 0)
return end-start+1;
else
return findLongest(array, start, end);
}
#include <iostream>
using namespace std;
void find( int *data, int &start, int &end )
{
// reflects the prefix sum until start - 1
int sumStart = 0;
// reflects the prefix sum until end
int sumEnd = 0;
for( int i = start; i <= end; i++ )
sumEnd += data[i];
while( start < end )
{
int length = end - start + 1;
int sum = 2 * ( sumEnd - sumStart );
if( sum == length )
break;
else if( sum < length )
{
// sum needs to increase; get rid of the lower endpoint
if( data[ start ] == 0 && data[ end ] == 1 )
{
// sumStart must be updated to reflect the new prefix sum
sumStart += data[ start ];
start++;
}
else
{
// sumEnd must be updated to reflect the new prefix sum
sumEnd -= data[ end ];
end--;
}
}
else
{
// sum needs to decrease; get rid of the higher endpoint
if( data[ start ] == 1 && data[ end ] == 0 )
{
// sumStart must be updated to reflect the new prefix sum
sumStart += data[ start ];
start++;
}
else
{
// sumEnd must be updated to reflect the new prefix sum
sumEnd -= data[ end ];
end--;
}
}
}
}
int main() {
int length;
cin >> length;
// get the data
int data[length];
for( int i = 0; i < length; i++ )
cin >> data[i];
// solve and print the solution
int start = 0, end = length - 1;
find( data, start, end );
if( start == end )
puts( "No soln" );
else
printf( "%d %d\n", start, end );
return 0;
}
#include <cstddef>
#include <bitset>
static const size_t N = 270;
void findLargestBalanced(std::bitset<N>& a, size_t& p1s, size_t& p2s)
{
// Step 1
size_t p1 = 0;
size_t p2 = N;
int d = 2 * a.count() - N;
bool flip = false;
if (d == 0) {
p1s = 0;
p2s = N;
return;
}
if (d < 0) {
flip = true;
d = -d;
a.flip();
}
// Step 2
bool next = true;
while (d > 0) {
if (p2 < N) {
next = a[p2];
}
--d;
--p2;
if (a[p2] == false) {
if (p2+1 < N) {
a[p2+1] = false;
}
int dd = 2;
while (dd > 0) {
dd += (a[--p2]? -1: 1);
}
a[p2+1] = next;
a[p2] = false;
}
}
// Step 3
p2s = p2;
p1s = p1;
do {
// Step 4
if (a[p2] == false) {
a[p2++] = true;
bool nextToRestore = a[p2];
a[p2++] = true;
int dd = 2;
while (dd > 0 && p2 < N) {
dd += (a[p2++]? 1: -1);
}
if (dd == 0) {
a[--p2] = nextToRestore;
}
}
else {
++p2;
}
// Step 5
if (a[p1++] == false) {
int dd = 2;
while (dd > 0) {
dd += (a[p1++]? -1: 1);
}
}
// Step 6
if (p2 - p1 > p2s - p1s) {
p2s = p2;
p1s = p1;
}
} while (p2 < N);
if (flip) {
a.flip();
}
}
def longestBalancedSubarray(A):
lo,hi = 0,len(A)-1
ones = sum(A);zeros = len(A) - ones
while lo < hi:
if ones == zeros: break
else:
if ones > zeros:
if A[lo] == 1: lo+=1; ones-=1
elif A[hi] == 1: hi+=1; ones-=1
else: lo+=1; zeros -=1
else:
if A[lo] == 0: lo+=1; zeros-=1
elif A[hi] == 0: hi+=1; zeros-=1
else: lo+=1; ones -=1
return(A[lo:hi+1])
public static void longestSubArrayWithSameZerosAndOnes() {
// You are given an array of 1's and 0's only.
// Find the longest subarray which contains equal number of 1's and 0's
int[] A = new int[] {1, 0, 1, 1, 1, 0, 0,0,1};
int num0 = 0, num1 = 0;
// First, calculate how many 0s and 1s in the array
for(int i = 0; i < A.length; i++) {
if(A[i] == 0) {
num0++;
}
else {
num1++;
}
}
if(num0 == 0 || num1 == 0) {
System.out.println("The length of the sub-array is 0");
return;
}
// Second, check the array to find a continuous "block" that has
// the same number of 0s and 1s, starting from the HEAD and the
// TAIL of the array, and moving the 2 "pointer" (HEAD and TAIL)
// towards the CENTER of the array
int start = 0, end = A.length - 1;
while(num0 != num1 && start < end) {
if(num1 > num0) {
if(A[start] == 1) {
num1--; start++;
}
else if(A[end] == 1) {
num1--; end--;
}
else {
num0--; start++;
num0--; end--;
}
}
else if(num1 < num0) {
if(A[start] == 0) {
num0--; start++;
}
else if(A[end] == 0) {
num0--; end--;
}
else {
num1--; start++;
num1--; end--;
}
}
}
if(num0 == 0 || num1 == 0) {
start = end;
end++;
}
// Third, expand the continuous "block" just found at step #2 by
// moving "HEAD" to head of the array and "TAIL" to the end of
// the array, while still keeping the "block" balanced(containing
// the same number of 0s and 1s
while(0 < start && end < A.length - 1) {
if(A[start - 1] == 0 && A[end + 1] == 0 || A[start - 1] == 1 && A[end + 1] == 1) {
break;
}
start--;
end++;
}
System.out.println("The length of the sub-array is " + (end - start + 1) + ", starting from #" + start + " to #" + end);