Arrays 寻找最大平衡子阵的空间有效算法?

Arrays 寻找最大平衡子阵的空间有效算法?,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

给定一个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) {
    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);