"Algorithm Competition·Quick 300 Questions" One question per day: "Minimum Interval"

" Algorithm Competition: 300 Quick Questions " will be published in 2024 and is an auxiliary exercise book for "Algorithm Competition" .
All questions are placed in the self-built OJ New Online Judge .
Codes are given in three languages: C/C++, Java, and Python. The topics are mainly mid- to low-level topics and are suitable for entry-level and advanced students.


" Minimum interval ", link: http://oj.ecustacm.cn/problem.php?id=1869

Question description

[Problem description] Given the position P[i] and category T[i] of N cows. The interval [L,R] satisfies all categories of cattle. Find the minimum length of the interval [L,R].
[Input format] The first line is a positive integer N, 1≤N≤50000. Next N lines, each line contains two positive integers P[i] and T[i], no more than 10^9.
[Output format] Output the minimum length.
【Input sample】

6
25 7
26 1
15 1
22 3
20 1
30 1

【Output sample】

4

answer

   This is a typical ruler-finding question. Use the speed pointer to scan the interval and calculate the minimum interval length that meets the requirements. The steps are:
   (1) Sort by the position of the cattle.
   (2) Use window [L, R] to traverse all intervals and find the minimum length of the interval that meets the requirements. L is the slow pointer, R is the fast pointer, and the initial value points to the first cow. First, let R go forward until the interval [L, R] just contains all categories (the total number is type_all). This is an interval that meets the requirements. Then let the following L go forward until the category is not enough for type_all. This means that the interval [L, R] does not meet the requirements. Next, let R go forward until the requirements are met again. When R reaches the position of the last cow and L reaches the last position that satisfies the requirements, all intervals that satisfy the requirements have been traversed. Compare the lengths of all intervals that meet the requirements and find the minimum length.
   The amount of calculation is equal to the sorting plus ruler method. The sorting is O(nlogn); the ruler method is O(n) because both L and R only go through once. The total complexity is O(nlogn).
[Key points] How to use the ruler and the speed pointer.

C++ code

   Use map to count the number of categories in the window [L, R].

#include<bits/stdc++.h>
using namespace std;
int main(){
    
    
    int n;    cin >> n;
    vector<pair<int,int>>a(n, pair<int,int>(0, 0));
    set<int>Type;                             //用set统计有多少类别
    for(int i = 0; i < n; i++){
    
    
        cin >> a[i].first >> a[i].second;
        Type.insert(a[i].second);             //Type.size()是类别总数
    }
    sort(a.begin(), a.end());                 //按first从小到大排序
    int L = 0, R = 0, ans = 1e9;
    int type_all = Type.size(), type_now = 0; //type_all是类别总数,type_now是[L,R]内的类别数量
    unordered_map<int,int> Cnt;               //Cnt统计当前窗口内出现的类别各有多少个
    while(L < n){
    
    
        while(R < n && type_now != type_all) //快指针R一直走,直到窗口包含所有类别
            if(Cnt[a[R++].second]++ == 0)    //统计R位置的类别出现次数,等于0表示没有出现过
                type_now++;                  //窗口内包含的类别数量加1
        if(type_now == type_all)             //满足条件
            ans = min(ans, a[R-1].first - a[L].first);  //计算区间长度,找最小的
        if(--Cnt[a[L++].second] == 0)        //去掉慢指针L位置的类别,然后L往前走一步
            type_now--;                      //如果这个类别的数量减到0,那么type_now减一
    }
    cout<<ans<<endl;
    return 0;
}

Java code

import java.util.*;
public class Main {
    
    
    public static void main(String[] args) {
    
    
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        List<Pair<Integer, Integer>> a = new ArrayList<>();
        Set<Integer> Type = new HashSet<>();       //用set统计有多少类别
        for (int i = 0; i < n; i++) {
    
    
            int first = input.nextInt();
            int second = input.nextInt();
            a.add(new Pair<>(first, second));
            Type.add(second);                     //Type.size()是类别总数
        }
        Collections.sort(a, (x, y) -> {
    
               //按first从小到大排序
            int cmp = x.getFirst().compareTo(y.getFirst());
            if (cmp != 0)  return cmp;
            else           return x.getSecond().compareTo(y.getSecond());
        });
        int L = 0, R = 0, ans = Integer.MAX_VALUE;
        int type_all = Type.size(), type_now = 0; //type_all是类别总数,type_now是[L,R]内的类别数量
        Map<Integer, Integer> Cnt = new HashMap<>();  //Cnt统计当前窗口内出现的类别各有多少个
        while (L < n) {
    
    
            while (R < n && type_now != type_all) {
    
       //快指针R一直走,直到窗口包含所有类别
                if (Cnt.getOrDefault(a.get(R).getSecond(), 0) == 0)  //统计R位置的类别出现次数,等于0表示没有出现过
                    type_now++;             //窗口内包含的类别数量加1
                Cnt.put(a.get(R).getSecond(), Cnt.getOrDefault(a.get(R).getSecond(), 0) + 1);
                R++;
            }
            if (type_now == type_all)            //满足要求
                ans = Math.min(ans, a.get(R - 1).getFirst() - a.get(L).getFirst());  //计算区间长度,找最小的
            Cnt.put(a.get(L).getSecond(), Cnt.getOrDefault(a.get(L).getSecond(), 0) - 1); //去掉慢指针L位置的类别
            if (Cnt.getOrDefault(a.get(L).getSecond(), 0) == 0)    
				type_now--;               //如果这个类别的数量减到0,那么type_now减一
            L++;                          //然后L往前走一步
        }
        System.out.println(ans);
    }
}
class Pair<A, B> {
    
    
    A first;
    B second;
    Pair(A first, B second) {
    
    
        this.first = first;
        this.second = second;
    }
    public A getFirst(){
    
     return this.first; }
    public B getSecond(){
    
    return this.second;}
}

Python code

  

from collections import defaultdict
def solve(n, a):
    type = set()                                # 用set统计有多少类别
    for i in range(n):   type.add(a[i][1])      # type.size()是类别总数
    a.sort()                                    # 按位置a[i][0]从小到大排序
    L, R = 0, 0
    ans = float("inf")
    type_all, type_now = len(type), 0          # type_all是类别总数,type_now是[L,R]内的类别数量
    cnt = defaultdict(int)                     # cnt统计当前窗口内出现的类别各有多少个
    while L < n:
        while R < n and type_now != type_all:   # 快指针R一直走,直到窗口包含所有类别
            if cnt[a[R][1]] == 0:               # 统计R位置的类别出现次数,等于0表示没有出现过
                type_now += 1                   # 窗口内包含的类别数量加1
            cnt[a[R][1]] += 1
            R += 1
        if type_now == type_all:                # 满足条件
            ans = min(ans, a[R-1][0] - a[L][0]) # 计算区间长度,找最小的
        cnt[a[L][1]] -= 1
        if cnt[a[L][1]] == 0:                   # 去掉慢指针L位置的类别,然后往前走一步
            type_now -= 1                       # 如果这个类别的数量减到0,那么type_now减一
        L += 1
    return ans
if __name__ == "__main__":
    n = int(input())
    a = []
    for i in range(n):  a.append(tuple(map(int, input().split())))
    ans = solve(n, a)
    print(ans)

Guess you like

Origin blog.csdn.net/weixin_43914593/article/details/132507378