【问题标题】:Algorithm: Find smallest contiguous array containing K 0's in array of 1's and 0's算法:在 1 和 0 的数组中找到包含 K 个 0 的最小连续数组
【发布时间】:2012-12-06 10:26:47
【问题描述】:

我只有 1 和 0 的数组。现在我想找到至少包含 K 个 0 的最小连续子集/子数组。

示例 数组是 1 1 0 1 1 0 1 1 0 0 0 0 1 0 1 1 0 0 0 1 1 0 0 1 0 0 0 和 K(6) 应该是 0 0 1 0 1 1 0 0 0 或 0 0 0 0 1 0 1 1 0....

我的解决方案

     Array: 1 1 0 1 1 0 1 1 0  0  0  0  1  0  1  1  0  0  0   1  1  0  0
     Index: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19  20 21 22 23
     Sum:   1 2 2 3 4 4 5 6 6  6  6  6  7  7  8  9  9  9  9  10 11 11 11
Diff(I-S):  0 0 1 1 1 2 2 2 3  4  5  6  6  7  7  7  8  9 10  10 10 11 12

对于 K(6)

从 9-15 开始 = 将差异存储在差异中。

下一步增加差异 8-15(指数差异) 8-14(比较指数差异)

所以继续寻找元素最少的元素...

我正在为此解决方案寻找更好的算法。

【问题讨论】:

  • 我相信你正在寻找一个 minimal contigious 子数组(否则问题很简单)
  • 是的,阿米特。我正在寻找连续数组...
  • 在您的问题正文中提及“最小”并将问题标题中的“最小子集”更改为“最短子串”会有所帮助。
  • 它不是一个字符串,我有一个数组...所以我只需要子集..
  • 好的,我已经修改了标题,希望现在更有意义

标签: arrays algorithm data-structures


【解决方案1】:

我相信您可以使用滚动窗口来做到这一点:

  1. 在给定的数组中,找到第一个出现的 0(比如在索引 i 处)。
  2. 继续扫描,直到您的窗口中包含k 0(例如,窗口结束于索引j)记录窗口长度(例如j-i+1=L)。
  3. 现在,丢弃索引 i 最左边的 0,并继续扫描直到找到下一个 0(比如在索引 i'
  4. 将位于j 的窗口的右端扩展到j',使0 的计数再次=k
  5. 如果新的窗口长度L'=j'-i'+1 更小,请更新它。

继续重复上述过程,直到j 到达数组末尾。

不需要额外的空间,这是O(N)时间复杂度,因为一个元素最多会被扫描两次。

【讨论】:

    【解决方案2】:

    有了额外的 O(k) 内存,你可以在 O(n) 时间内完成。这是 java 代码。你正在做的是,如果 a[i]==0 那么你检查队列的第一个元素在哪里指向。如果位置差异小于最小值,则更新答案。

    Queue<Integer> queue =new LinkedList<Integer>();
    int i=0;
    while(queue.size()<k&&i<n)
    {
    if(a[i]==0)
    {
    queue.add(i);
    }
    i++;
    }
    if(i==n&&queue.size()<k)
    System.out.println("Insufficient 0''s");
    int ans=i-1-queue.peek();
    for(int j=i;j<n;j++)
    {
    if(a[i]==0)
    {
    queue.poll();
    queue.add(i);
    ans=Math.min(ans,i-queue.peek());
    }
    }
    System.out.println(ans);
    

    编辑:解释

    我们维护一个队列,该队列由所有位置为 0 的位置组成,并且我们将队列大小限制为 k。所以最初在 while 循环中,我们用前 k 个索引填充队列。如果看到所有元素后队列大小当然小于 k,那么这是不可能的。之后,我们继续遍历所有剩余的元素。每次看到 0 时,我们都会计算子序列的长度 (i-queue.peek()) 并找到最小值。此外,我们删除第一个元素,然后再次添加最新索引,保持队列大小

    【讨论】:

    • @Vishal :我已经用解释更新了代码。现在对你有意义吗?
    【解决方案3】:

    完整的python代码:

    >>> A = "1 1 0 1 1 0 1 1 0  0  0  0  1  0  1  1  0  0  0   1  1  0  0".split()
    >>> A = map(int, A)
    >>> zero_positions = [i for i, x in enumerate(A) if x == 0]
    >>> k = 3
    >>> containing_k_zeros_intervals = zip(zero_positions, zero_positions[k:])
    >>> min(b - a for a, b in containing_k_zeros_intervals)
    3
    

    【讨论】:

    • 如果您想提取区间而不仅仅是长度,请将 b - a 更改为 (a, b)
    • 不会取 (a,b) 的最小值以按字典顺序生成最小对吗?
    • 类似 min([(a, b) for a, b in contains_k_zeros_intervals], key = lambda (a, b): b-a) 的东西?
    • 抱歉,我的意思是将 b - a 更改为 (b - a, a, b)。感谢您关注 wye.bee :)
    【解决方案4】:
    1. 从头开始扫描数组,找到索引,直到我们得到 k 个零。

    有两个指针。

    现在 ptr1 位于第一个零出现的索引处。 开始 = ptr1

    ptr2 位于我们找到 k 个 0 的索引处。

    结束 = ptr2; a) 增加 ptr1。

    b ) 从 ptr2+1 找到索引,直到我们找到 k 个 0。

    c) 假设在 ptr3 我们找到 K 个 0。如果 ptr3-ptr1

    重复步骤 a -c 直到列表结束。

    最后,start 和 end 会有 k 个 0 的索引。

    【讨论】:

      猜你喜欢
      • 2020-01-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-04
      • 2012-10-18
      • 1970-01-01
      • 1970-01-01
      • 2019-12-03
      相关资源
      最近更新 更多