【问题标题】:Given an array find the number of sub arrays with m odd numbers?给定一个数组,找出具有 m 个奇数的子数组的数量?
【发布时间】:2017-08-12 01:38:34
【问题描述】:

示例输入: 1 2 3 4 5(数组元素) m = 1(奇数) 样本输出: 8。 子数组是 [[1], [1,2], [2,3], [2,3,4], [3], [3,4], [4,5], [5]]

这是我的实现。在最坏的情况下,需要 O(n+n^2)。有什么方法可以优化这段代码吗?

int main() {
    int n, *a, count1=0, m, *dp;
    cin>>n;
    a = new int[n];
    dp =new int[n];

    for(int i=0; i<n; i++) {
        cin >> a[i];
    }

    cin >> m;

    for(int i=0; i<n; i++){
        if(a[i]%2==1) {
            count1++;
        }

        dp[i] =count1;
    }

    int prev;
    long count=0;

    for(int i=0; i<n; i++) {
        prev= i==0 ? 0:dp[i-1];
        for(int j=i; j<n; j++) {
            if((dp[j] - prev) == m){
                count++;
            }

            if(dp[j] - prev > m){
                break;
            }
        }
    }
    cout<<count;
}

【问题讨论】:

  • 作为一个兴趣点,大 O 表示法往往只使用最重要的术语,因此您的算法将是 O(n^2)。

标签: c++ arrays algorithm


【解决方案1】:

这可以在O(n) 中解决。首先生成一个奇数之间间隙长度的数组,将两端计算为隐式奇数。在这种情况下,该数组是g = [0,1,1,0]。然后我们对(g[i]+1)*(g[i+m]+1) 求和,因为这表示有多少子数组从i'th 奇数开始或之前,并在i+m'th 奇数之后或之后结束。

在这种情况下,我们得到1*2 + 2*2 + 2*1 = 8

其他解释 想想想要的子数组列表。每个都从某个地方开始,包括m 奇数,然后在其他地方结束。让我们根据它们包含的奇数串将它们分组。每个组包含一些iith 奇数,并以i+m-1'th 奇数结束。起点是i-1th 和ith 奇数之间的每个偶数,以及ith 奇数本身。这是ith 奇数 + 1 之前的差距大小。或g(i)+1 在我的计算中。类似地,终点在i+m-1th 奇数,或者在它与i+mth 奇数之间的所有偶数处。这比i+m-1th 和i+mth 奇数之间的差距大1。在我的计算中是g(i+m)+1。因此,该组中的数字是起点数乘以终点数。这是(g(i)+1)*(g(i+m)+1)。将其添加到所有起点i,我们就有了答案。

我忽略了一个重要的细节。也就是说,我假设包含奇数,所以0 &lt; m。如果m = 0 则计算完全改变。答案是1 + sum(g(i)*(g(i)-1)/2)

【讨论】:

  • 你能详细解释一下吗?
  • @AkshayMathur 这不是更多解释的情况。而是替代解释,直到点击其他人没有的地方。我会添加第二个。
  • discuss.codechef.com/questions/103416/contiguous-subarray 阅读本文以获得更清晰的信息。
  • i 索引g 中的最后一个数字时,您如何获得g[i+m]g[i+m] 将是一个不存在的元素。你在绕行吗?
  • @ginna 你从哪里得知i 正在索引g 中的最后一个数字?我只是使用i 作为索引变量。它从 0 开始,一直到 i+m 到达数组的末尾。无需包装。
【解决方案2】:

你可以很容易地得到 O(n log n)。对您的代码的一个简单改进是,在您的内部循环中(在 j 上),而不是一个接一个地计数,您在区间 [i, n] 上进行二进制搜索以找到导致 m 奇数的第一个位置,以及产生 m+1 个奇数的第一个位置;然后减去它们。

但是,要做到这一点,您需要一个 sum[] 数组,其中第 i 个位置显示区间 [0, i] 中奇数的个数。这可以用一个 for 循环在 O(n) 中预先计算。

现在你在二分搜索中像这样使用它:

for(int i = 0; i < n; i++){
    int lo = i;
    int hi = n;

    while(lo < hi){
        int mid = (lo + hi)/2;
        int count = sum[mid];
        if(i > 0) count -= sum[i - 1];

        //count shows number of odd in the interval [i, mid]
        if(mid >= m){
            hi = mid;
        } 
        else{
            lo = mid + 1;
        }
    }

    int first_with_m = lo;

    //do another binary search to find first_with_m_plus_one

    answer += first_with_m_plus_one - first_with_m;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-03
    • 2021-03-09
    • 2014-09-04
    • 2016-03-12
    • 1970-01-01
    • 2019-06-06
    • 2022-12-21
    相关资源
    最近更新 更多