二进制数组的最长切片,可以分成两部分

时间:2015-04-23 14:37:05

标签: algorithm

如何找到可以分成两部分的二进制数组的最长切片:在左边部分,0应该是领导者;在正确的部分,1应该是领导者? 例如 : [1,1,0,1,0,0,1,1]应该返回7,因此第一部分是[1,0,1,0,0],第二部分是[1,1]

我尝试了以下soln并且在一些测试用例中取得了成功,但我认为它效率不高:

  public static int solution(int[] A)
        {
            int length = A.Length;
            if (length <2|| length>100000)
                return 0;
            if (length == 2 && A[0] != A[1])
                return 0;
            if (length == 2 && A[0] == A[1])
                return 2;
            int zerosCount = 0;
            int OnesCount = 0;
            int start = 0;
            int end = 0;
            int count=0;

            //left hand side
            for (int i = 0; i < length; i++)
            {
                end = i;
                if (A[i] == 0)
                    zerosCount++;
                if (A[i] == 1)
                    OnesCount++;
                count = i;
                if (zerosCount == OnesCount )
                {
                    start++;
                    break;
                }

            }

            int zeros = 0;
            int ones = 0;

            //right hand side
            for (int j = end+1; j < length; j++)
            {
                count++;
                if (A[j] == 0)
                    zeros++;
                if (A[j] == 1)
                    ones++;
                if (zeros == ones)
                {
                    end--;
                    break;
                }
            }
            return count;
        }

2 个答案:

答案 0 :(得分:5)

我同意蛮力是时间复杂度:O(n ^ 3)。

但这可以在线性时间内解决。我在C中实现了它,这里是代码:

int f4(int* src,int n)
{
    int i;
    int sum;
    int min;
    int sta;
    int mid;
    int end;

    // Find middle
    sum = 0;
    mid = -1;
    for (i=0 ; i<n-1 ; i++)
    {
        if (src[i]) sum++;
        else sum--;

        if (src[i]==0 && src[i+1]==1)
        {
            if (mid==-1 || sum<min)
            {
                min=sum;
                mid=i+1;
            }
        }
    }
    if (mid==-1) return 0;

    // Find start
    sum=0;
    for (i=mid-1 ; i>=0 ; i--)
    {
        if (src[i]) sum++;
        else sum--;

        if (sum<0) sta=i; 
    }

    // Find end
    sum=0;
    for (i=mid ; i<n ; i++)
    {
        if (src[i]) sum++;
        else sum--;

        if (sum>0) end=i+1; 
    }

    return end-sta;
}

此代码经过测试:暴力结果与此功能相对应。他们有相同的结果。我测试了10个元素(1024种组合)的所有有效数组。

如果您喜欢这个答案,请不要忘记投票:)

答案 1 :(得分:3)

正如所承诺的那样,继续更新:

我找到了一个简单的线性时间复杂算法来解决这个问题。

数学: 将输入定义为int []位,我们可以定义此函数:

f(x) = {bits[x] = 0: -1; bits[x] = 1: 1}

下一步是为给定的输入创建此函数的基本积分:

F(x) = bits[x] + F(x - 1)
F(-1) = 0
This integral is from 0 to x.

F(x)只代表count(bits , 1 , 0 , x + 1) - count(bits , 0 , 0 , x + 1)的数量。这可用于定义以下函数:F(x , y) = F(y) - F(x),它与count(bits , 1 , x , y + 1) - count(bits , 0 , x , y + 1)相同(1的数量减去[x,y]范围内的0的数量 - 这只是为了说明如何算法基本上有效)。

由于搜索到的字段序列必须满足以下条件:在[start , mid]范围内0必须是前导,并且在[mid , end]范围内1必须是前导且end - start + 1必须是搜索到的mid最大可能值必须满足以下条件:F(mid) < F(start) AND F(mid) < F(end)。因此,第一步是搜索“F(x)”的最小值,这将是中间值(每个其他点必须>>最小值,因此将导致更小/同样大的范围[end - start + 1]。注意:此搜索可以通过考虑以下因素进行优化:f(x)始终为1-1。因此,如果f(x)为下一个{{1}返回1位1}}步骤,具有最小值的下一个可能索引将是n(自上一个最小值意味着'n'1s,之后需要'n'-1s才能达到最小值 - 或至少'n'个步骤)。

给定n * 2的最小值为'x',我们可以简单地找到F(x)start(最大/最小值b,s∈[0,长度(位) - 1]这样:endF(s) > F(mid),可以在线性时间内找到。

伪代码:

F(b) > F(mid)