【问题标题】:Longest slice of a binary array that can be split into two parts可以分成两部分的二进制数组的最长切片
【发布时间】:2015-07-01 19:56:43
【问题描述】:

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

我尝试了以下解决方案,它在某些测试用例中成功,但我认为它效率不高:

  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;
        }

【问题讨论】:

  • 通过编码,你尝试过什么?

标签: algorithm


【解决方案1】:

按照承诺,更新如下:

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

数学: 将输入定义为 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) 相同([x , y] 范围内 1 的数量减去 0 的数量 - 这只是为了说明算法的基本工作原理)。

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

给定F(x) 的最小值'x',我们可以简单地找到startend(最大/最小值 b,s ∈ [0 , length(bits) - 1] 使得:@ 987654342@和F(b) &gt; F(mid),可以在线性时间内找到。

伪代码:

input: int[] bits
output: int

//input verification left out

//transform the input into F(x)
int temp = 0;
for int i in [0 , length(bits)]
    if bits[i] == 0
         --temp;
    else
         ++temp;

//search the minimum of F(x)
int midIndex = -1
int mid = length(bits)
for int i in [0 , length(bits - 1)]
    if bits[i] > mid
         i += bits[i] - mid //leave out next n steps (see above)
    else if bits[i - 1] > bits[i] AND bits[i + 1] > bits[i]
         midIndex = i
         mid = bits[i]

if midIndex == -1
    return //only 1s in the array


//search for the endindex    
int end
for end in [length(bits - 1) , mid]
    if bits[end] > mid
        break
    else
        end -= mid - bits[end] //leave out next n searchsteps

//search for the startindex
int start
for start in [0 , mid]
    if bits[start] > mid
         break
    else
         start += mid - bits[start]

 return end - start

【讨论】:

    【解决方案2】:

    我同意蛮力是时间复杂度: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 种组合)。

    如果你喜欢这个答案,别忘了投票 :)

    【讨论】:

      猜你喜欢
      • 2018-12-25
      • 1970-01-01
      • 2012-10-31
      • 1970-01-01
      • 2018-07-30
      • 2020-09-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多