簡體   English   中英

查找具有指定數量奇數的子數組的數量

[英]find number of subarrays with specified number of odd integers

給定一個整數數組和一個整數 m,如何找到包含 m 個奇數整數的所有子數組? 如果我的還不夠,下面是完整問題的詳細描述。 這個問題有沒有比 n^2 更快的解決方案? 我下面的解決方案似乎是 n^2,我不確定如何進一步優化它。

https://github.com/cem3394/HR-Haskell/blob/master/beautifulSubarrays.hs

    static long beautifulSubarrays(int[] a, int m) {
    int sum = 0;
    for (int i = 0; i < a.length; i++){
        for (int j = i, c =0; j < a.length; j++){
            if (a[j] %2 !=0){
                c++;
            }
            if ((c==m) && (z==j)){
                over = true;
                sum++;
                break
            }
            boolean over = false;
            if (over) break;
            for (int z = i, c = 0; z <= j; z++){
                if (a[z]%2 != 0){
                    c++;

                }
                if (c>m){
                    over = true;
                    break;

                }
                if ((c==m) && (z==j)){
                    over = true;
                    sum++;
                    break;
                }
            }
        }
    }
    return sum;


    }

這是兩點方法的任務。

制作兩個索引 - L 和 R。

將 L 設置為 0 並將 R 從 0 向右移動,在 Od 計數器中計算奇數。 當 Od 變為 m 時,記住 R 位置為 R0。 進一步移動 R 直到遇到新的奇數。

記住 L 位置為 L0 並遞增 L 直到遇到奇數(如果 A[L0] 是奇數,則保持不變)。

現在所有從L0..L范圍開始到R0..R-1范圍結束的子數組都包含 m 個奇數。 Cnt = (L-L0+1) * (R-R0)這樣的子數組:

m=3 
       L0 L        R0           R
i      0  1  2  3  4  5  6  7  8 
A[i]   4  1  3  2  5  6  2  2  3

所有從 0..1 開始到 4..7 結束的子數組,包含 3 個奇數,這里有 2 個開始索引和 4 個結束索引,所以Cnt = 8

遞增 L,再次記住 R0 重復此過程直到數組結束,為結果設置的每個范圍添加 Cnt

指針只遍歷數組一次,復雜度是線性的。

我在任何地方都找不到對這個問題的足夠解釋所以我已經盡最大努力一步一步解釋這個問題。

這是這個問題的 JS 版本,時間復雜度為O(n)

輸入: arr - 要處理的數組,m - 要存在的整數數

返回: 具有恰好 m 個奇數的唯一子數組的數量

function beautifulArray(arr, m) {
  var noOfOddNumbersSoFar = 0;
  var ans = 0;
  var save = []; // Save possible number of sub arrays till i with m odd numbers

  for (var i = 0; i < arr.length; i++) {
    if (save[noOfOddNumbersSoFar]) {
      save[noOfOddNumbersSoFar]++;
    } else {
      save[noOfOddNumbersSoFar] = 1;
    }

    noOfOddNumbersSoFar += arr[i] % 2 == 0 ? 0 : 1;

    if (noOfOddNumbersSoFar >= m) {
      ans += save[noOfOddNumbersSoFar - m];
    }
  }

  return ans;
}

解釋我們在這里做的是計算可以形成的子數組的總數,直到我們達到 m 個奇數並將其保存到名為save 的數組中。 我們只需將此添加到我們的答案中即可獲得可以形成的子數組的總數。 我們這樣做直到我們到達最后一個元素。

考慮以下輸入

arr = [2,2,5,6,9,2,11];
m = 2;

第1步:

noOfOddNumbersSoFar = 0
save[noOfOddNumbersSoFar] is set to 1. i.e, save = [1]
i = 0
arr[i] is 2 (even)
noOfOddNumbersSoFar remains 0

第2步:

noOfOddNumbersSoFar = 0
save[noOfOddNumbersSoFar] is set to 2. i.e, save = [2]
i = 1
arr[i] is 2 (even)
noOfOddNumbersSoFar remains 0

第 3 步:

noOfOddNumbersSoFar = 0
save[noOfOddNumbersSoFar] is set to 3. i.e, save = [3]
i = 2
arr[i] is 5 (odd)
noOfOddNumbersSoFar is set to 1

第四步:

noOfOddNumbersSoFar = 1
save[noOfOddNumbersSoFar] is set to 1. i.e, save = [3, 1]
i = 3
arr[i] is 6 (even)
noOfOddNumbersSoFar remains 1

第 5 步:

noOfOddNumbersSoFar = 1
save[noOfOddNumbersSoFar] is set to 2. i.e, save = [3, 2]
i = 4
arr[i] is 9 (odd)
noOfOddNumbersSoFar is set to 2

noOfOddNumbersSoFar is >= m(2)
  noOfOddNumbersSoFar - m 
  So we take the number of possible subarrays from the saved variable save[0] and add it to ans. ans = 3

Here 3 denotes [2, 2, 5, 6, 9], [2, 5, 6, 9] and [5, 6, 9].

第 6 步:

noOfOddNumbersSoFar = 2
save[noOfOddNumbersSoFar] is set to 1. i.e, save = [3, 2, 1]
i = 5
arr[i] is 2 (even)
noOfOddNumbersSoFar remains 2

noOfOddNumbersSoFar is >= m(2)
  noOfOddNumbersSoFar - m is still 0
  So we take the number of possible subarrays from the saved variable save[0] and add it to ans. ans = 3 + 3 = 6

We are adding 3 more to the ans. It denotes three more sub arrays which can meet the condition. They are [2, 2, 5, 6, 9, 2], [2, 5, 6, 9, 2] and [5, 6, 9, 2].

We have addressed [2, 2, 5, 6, 9], [2, 5, 6, 9], [5, 6, 9], [2, 2, 5, 6, 9, 2], [2, 5, 6, 9, 2] and [5, 6, 9, 2] so far. // ans = 6

第 7 步:

noOfOddNumbersSoFar = 2
save[noOfOddNumbersSoFar] is set to 2. i.e, save = [3, 2, 2]
i = 6
arr[6] is 11 (odd)
noOfOddNumbersSoFar is set to 3

noOfOddNumbersSoFar is >= m(2)
noOfOddNumbersSoFar - m is still 1
So we take the number of possible subarrays from the saved variable save[1] and add it to ans. ans = 6 + 2 = 8

We are adding 2 more to the ans. It denotes two more sub arrays which can meet the condition. They are [6, 9, 2, 11] and [9, 2, 11].

We have addressed [2, 2, 5, 6, 9], [2, 5, 6, 9], [5, 6, 9], [2, 2, 5, 6, 9, 2], [2, 5, 6, 9, 2], [5, 6, 9, 2], [6, 9, 2, 11] and [9, 2, 11] so far. // ans = 8

由於沒有更多的元素,沒有更多的子數組可以滿足這個條件,返回 ans 為 8。

想到了一個算法,但沒有機會驗證復雜度(我認為應該是 O(n) )

找出所有“最小”子數組

目的是找出所有以奇數開頭和結尾的子數組。

以 O(n) 方式實現它的一種方法是:對數組進行一次傳遞,並記錄所有奇數索引:

例如輸入[ 2,3,4,6,7,1,10 ] ,你應該能夠得到[1,4,5] (索引 1,4,5 是奇數)

假設你想在子數組中有2個奇數,它是[1,4][4,5]

找出每個子數組的擴展形式

基本思想是,對於每個最小子數組,您可以包括前面和后面的奇數。

以數組[4..5]為例:

[ 2,3,4,6,7,1,10 ]
          ^ ^

您可以選擇在偶數前包含 0、1 或 2。 同時,您可以選擇包含 0 或 1 個后繼偶數。

這意味着,對於這個特定的子數組,有 2*3 = 6 個“擴展形式”

通過將子[-1,1,4,5,7]索引從[1,4,5]稍微修改為[-1,1,4,5,7] ,可以輕松找到前面/后面偶數的數量的快速方法。 索引 4 之前的偶數前面的數字是 4-1,即 3,索引 5 后面的偶數是 7-5,即 2。

通過總結每個最小子數組的擴展形式的數量,你可以得到你想要的結果。

import java.util.HashSet;

public class subarray {

    public static void main(String[] args) {
        //        int numbers[] = {1, 2, 3, 4};
        //        int numbers[] = {6, 3, 5, 8};
        //        int kk = 1;
        int numbers[] = {2, 1, 2, 1, 3};
        int kk = 2;
        HashSet<Integer> evenElements = new HashSet<>();
        HashSet<Integer> oddElements = new HashSet<>();
        int count = 0;
        for (int i = 0; i < numbers.length; i++) {
            if (numbers[i] % 2 == 0) {
                evenElements.add(numbers[i]);
            } else {
                oddElements.add(numbers[i]);
            }
        }
        for (int i = 0; i < numbers.length; i++) {
            for (int j = i + 1; j < numbers.length; j++) {
                int odd = 0;
                for (int k = i; k <= j; k++) {
                    boolean flag = true;
                    for (int l = 0; l < i; l++) {
                        if (numbers[l] == numbers[i] && numbers[l + 1] == numbers[j]) {
                            flag = false;
                        }
                    }
                    if (flag) {
                        if (numbers[k] % 2 != 0) {
                            odd = odd + 1;
                        }
                    }
                }
                if (odd != 0 && odd <= kk) {
                    count = count + 1;
                }
            }
        }
        System.out.println(count + oddElements.size() + evenElements.size());
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM