解题思路

这是一个区间查找问题,需要找到包含所有不同数字的最小区间。具体要求:

  1. 序列中的数字范围在
  2. 找到最小的连续区间,使其包含所有不同的数字
  3. 如果有多个这样的区间,按照出现顺序输出所有区间

解决方案:

  1. 使用双指针(滑动窗口)技术
  2. 对原始数字进行离散化处理,减少空间占用
  3. 使用计数数组记录每个数字的出现次数
  4. 维护最小区间长度和所有符合条件的区间

代码

#include <bits/stdc++.h>
using namespace std;

const int N = 5000010;

int main() {
    int n;
    scanf("%d", &n);
    
    // 离散化处理
    vector<int> a(n + 1);
    map<int, int> mp;
    vector<int> count(n + 1, 0);
    int unique_nums = 0;
    
    for(int i = 1; i <= n; i++) {
        int x;
        scanf("%d", &x);
        if(mp.count(x) == 0) {
            mp[x] = unique_nums++;
        }
        a[i] = mp[x];
        count[a[i]]++;
    }
    
    // 寻找最小区间
    vector<pair<int, int>> intervals;
    int min_len = n + 1;
    int l = 1, r = n;
    
    // 初始化右边界
    while(count[a[r]] > 1) {
        count[a[r]]--;
        r--;
    }
    
    while(true) {
        // 调整左边界
        while(count[a[l]] > 1) {
            count[a[l]]--;
            l++;
        }
        
        int curr_len = r - l + 1;
        if(curr_len < min_len) {
            min_len = curr_len;
            intervals.clear();
            intervals.push_back({l, r});
        } else if(curr_len == min_len) {
            intervals.push_back({l, r});
        }
        
        // 移动窗口
        int removed = a[l];
        count[a[l]]--;
        l++;
        
        if(r == n) break;
        while(r < n) {
            r++;
            count[a[r]]++;
            if(a[r] == removed) break;
        }
        if(a[r] != removed) break;
    }
    
    // 输出结果
    printf("%d %d\n", min_len, (int)intervals.size());
    for(int i = 0; i < intervals.size(); i++) {
        if(i > 0) printf(" ");
        printf("[%d,%d]", intervals[i].first, intervals[i].second);
    }
    printf("\n");
    
    return 0;
}
import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        
        // 离散化处理
        int[] a = new int[n + 1];
        Map<Integer, Integer> mp = new HashMap<>();
        int[] count = new int[n + 1];
        int uniqueNums = 0;
        
        // 每行读取一个数
        for(int i = 1; i <= n; i++) {
            int x = Integer.parseInt(br.readLine());
            if(!mp.containsKey(x)) {
                mp.put(x, uniqueNums++);
            }
            a[i] = mp.get(x);
            count[a[i]]++;
        }
        
        // 寻找最小区间
        List<int[]> intervals = new ArrayList<>();
        int minLen = n + 1;
        int l = 1, r = n;
        
        // 初始化右边界
        while(count[a[r]] > 1) {
            count[a[r]]--;
            r--;
        }
        
        while(true) {
            // 调整左边界
            while(count[a[l]] > 1) {
                count[a[l]]--;
                l++;
            }
            
            int currLen = r - l + 1;
            if(currLen < minLen) {
                minLen = currLen;
                intervals.clear();
                intervals.add(new int[]{l, r});
            } else if(currLen == minLen) {
                intervals.add(new int[]{l, r});
            }
            
            // 移动窗口
            int removed = a[l];
            count[a[l]]--;
            l++;
            
            if(r == n) break;
            while(r < n) {
                r++;
                count[a[r]]++;
                if(a[r] == removed) break;
            }
            if(a[r] != removed) break;
        }
        
        // 使用StringBuilder加快输出
        StringBuilder sb = new StringBuilder();
        sb.append(minLen).append(" ").append(intervals.size()).append("\n");
        for(int i = 0; i < intervals.size(); i++) {
            if(i > 0) sb.append(" ");
            sb.append("[").append(intervals.get(i)[0]).append(",").append(intervals.get(i)[1]).append("]");
        }
        System.out.println(sb);
    }
}
``` python []
import sys
input = sys.stdin.readline
def solve():
    n = int(input())
    
    # 离散化处理
    a = [0] * (n + 1)
    mp = {}
    count = [0] * (n + 1)
    unique_nums = 0
    
    nums = [int(input()) for _ in range(n)]
    for i in range(n):
        x = nums[i]
        if x not in mp:
            mp[x] = unique_nums
            unique_nums += 1
        a[i + 1] = mp[x]
        count[a[i + 1]] += 1
    
    # 寻找最小区间
    intervals = []
    min_len = n + 1
    l, r = 1, n
    
    # 初始化右边界
    while count[a[r]] > 1:
        count[a[r]] -= 1
        r -= 1
    
    while True:
        # 调整左边界
        while count[a[l]] > 1:
            count[a[l]] -= 1
            l += 1
        
        curr_len = r - l + 1
        if curr_len < min_len:
            min_len = curr_len
            intervals = [[l, r]]
        elif curr_len == min_len:
            intervals.append([l, r])
        
        # 移动窗口
        removed = a[l]
        count[a[l]] -= 1
        l += 1
        
        if r == n:
            break
        while r < n:
            r += 1
            count[a[r]] += 1
            if a[r] == removed:
                break
        if a[r] != removed:
            break
    
    # 输出结果
    print(min_len, len(intervals))
    print(' '.join(f'[{interval[0]},{interval[1]}]' for interval in intervals))

solve()

算法及复杂度

  • 算法:双指针(滑动窗口)+ 离散化
  • 时间复杂度: - 每个位置最多被访问常数次
  • 空间复杂度: - 需要存储离散化映射和计数数组