最大有多少个连续的子数组n个唯一数字

时间:2018-10-01 11:15:55

标签: arrays algorithm sub-array

我在网上发现了编程难题,想知道是否有更有效的解决方案。

问题: 系统会为您提供n个数字的列表以及一个数字X,该数字X表示连续子数组中可以包含的最大不同数字数。我们需要计算所有满足X条件的连续子​​数组。

输入 第一行是两个数字n和x。子数组中数字的数量和最大唯一数字。

示例:

5 2
1 2 3 1 1
ans = 10
explanation: ([1],[2],[3],[1],[1],[1,2],[2,3],[3,1],[1,1],[3,1,1])

我的方法 使用两个循环循环遍历列表的所有子数组,并计算有关子数组中唯一编号的数量(使用一组)。当然,必须有一种更有效的方法来计算此值吗?抱歉,如果这个问题不属于这里,请随时进行编辑。

编辑:nellex的更正后的代码有时会给出错误的答案

int main() {
    int n, x;
    cin >> n >> x;

    vector<int> a;
    for (int i = 1; i <= n; i++) {
        int b;
        cin >> b;
        a.push_back(b);
    }

    int ans = 0, end = 1;
    set<int> uniq;
    map<int, int> freq;
    for (int start = 0; start < n; start++) {
        cout << start << " and end=" << end << endl;
        while (uniq.size() <= x && end < n) {
            if (uniq.size() == x && freq[a[end]] == 0) {
                break;
            }
            uniq.insert(a[end]);
            freq[a[end]]++;
            end++;
        }
        cout << "added " << end << " - " << start << " to ans" << endl;
        ans += end - start;
        freq[a[start]]--;
        if (freq[a[start]] == 0) {
            uniq.erase(a[start]);
        }
    }
    cout << ans;
}

编辑: 第一个测试用例约束:

1≤k≤n≤100

1≤xi≤10

最大限制:

1≤k≤n≤5⋅10^5

1≤xi≤10^9

2 个答案:

答案 0 :(得分:2)

滑动窗口方法将更适合解决此问题,这将使我们能够通过使用Set和Map在 O(n * log(n))中进行解决:{{ 3}}

int main() {
    int n, x;
    cin >> n >> x;

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

    int end = 0;
    long long ans = 0;

    set<int> uniq;
    map<int, int> freq;
    for(int start = 0; start < n; start++) {
        while(uniq.size() <= x && end < n) {
            if(uniq.size() == x && freq[a[end]] == 0) {
                break;
            }
            uniq.insert(a[end]);
            freq[a[end]]++;
            end++;
        }
        ans += end - start;
        freq[a[start]]--;
        if(freq[a[start]] == 0) {
            uniq.erase(a[start]);
        }
    }
    cout << ans;
}

该算法的工作方式是,对于由索引 start 定义的每个元素,即a[start],我们尝试查找从start开始的最大子数组这样子数组中的唯一元素是 <= x 。如果所标识的子数组的大小为S,则我们知道元素a[start]将成为S子数组的一部分,从索引start开始。

如果我们针对给定的示例进行试运行,

  • 当start = 1时,我们将生成子数组{[1],[1,2]}
  • 当start = 2时,我们将生成子数组{[2],[2、3]}
  • 当start = 3时,我们将生成子数组{[3],[3、1],[3、1、1]}
  • 当start = 4时,我们将生成子数组{[1],[1,1]}
  • 当start = 5时,我们将生成子数组{[1]}

答案 1 :(得分:1)

我们可以通过保留两个指针O(n)p_lp_r来解决这个问题,这两个指针都使数组前移,同时更新频率计数h[e] ,对于遇到的每个元素以及当前的唯一项数k

例如:

5 2
1 2 3 1 1

让我们看看每次迭代

k = 0
h = {}
total = 0
p_r = -1
p_l = -1

1:   p_r = 0
     h = {1:1}
     k = 1
     total = 1

2:   p_r = 1
     h = {1:1, 2:1}
     k = 2
     total = 1 + 2 = 3

3:   p_r = 2
     h = {1:1, 2:1, 3:1}
     k = 3

  => move p_l until k equals X:
     p_l = 0
     h = {1:1-1=0, 2:1, 3:1}
     k = 3 - 1 = 2

     total = 3 + 2 = 5

1:   p_r = 3
     h = {1:1, 2:1, 3:1}
     k = 3

  => move p_l until k equals X:
     p_l = 1
     h = {1:1, 2:1-1=0, 3:1}
     k = 3 - 1 = 2

     total = 5 + 2 = 7

1:   p_r = 4
     h = {1:2, 2:0, 3:1}
     k = 2
     total = 7 + 3 = 10