"Concurso de algoritmos · 300 preguntas rápidas" Una pregunta por día: "Intervalo mínimo"

" Competencia de algoritmos: 300 preguntas rápidas " se publicará en 2024 y es un libro de ejercicios auxiliar para la "Competencia de algoritmos" .
Todas las preguntas se colocan en el nuevo juez en línea del DO de creación propia .
Los códigos se proporcionan en tres lenguajes: C/C++, Java y Python. Los temas son principalmente temas de nivel medio a bajo y son adecuados para estudiantes principiantes y avanzados.


" Intervalo mínimo ", enlace: http://oj.ecustacm.cn/problem.php?id=1869

Descripción de la pregunta

[Descripción del problema] Dada la posición P[i] y la categoría T[i] de N vacas. El intervalo [L,R] satisface todas las categorías de ganado. Encuentre la longitud mínima del intervalo [L,R].
[Formato de entrada] La primera línea es un número entero positivo N, 1≤N≤50000. Las siguientes N líneas, cada línea contiene dos números enteros positivos P [i] y T [i], no más de 10 ^ 9.
[Formato de salida] Genera la longitud mínima.
【Muestra de entrada】

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

【Muestra de salida】

4

respuesta

   Esta es una pregunta típica de búsqueda de reglas: utilice el puntero de velocidad para escanear el intervalo y calcular la longitud mínima del intervalo que cumpla con los requisitos. Los pasos son:
   (1) Ordenar por la posición del ganado.
   (2) Utilice la ventana [L, R] para recorrer todos los intervalos y encontrar la longitud mínima del intervalo que cumpla con los requisitos. L es el puntero lento, R es el puntero rápido y el valor inicial apunta a la primera vaca. Primero, deje que R avance hasta que el intervalo [L, R] contenga todas las categorías (el número total es type_all). Este es un intervalo que cumple con los requisitos. Luego deje que la siguiente L avance hasta que la categoría no sea suficiente para type_all. Esto significa que el intervalo [L, R] no cumple con los requisitos. A continuación, deje que R avance hasta que se cumplan los requisitos nuevamente. Cuando R alcanza la posición de la última vaca y L alcanza la última posición que satisface los requisitos, se han atravesado todos los intervalos que satisfacen los requisitos. Compare las longitudes de todos los intervalos que cumplen los requisitos y encuentre la longitud mínima.
   La cantidad de cálculo es igual al método de clasificación más regla. La clasificación es O(nlogn); el método de la regla es O(n) porque tanto L como R solo pasan una vez. La complejidad total es O (nlogn).
[Puntos clave] Cómo utilizar la regla y el puntero de velocidad.

código C ++

   Utilice el mapa para contar el número de categorías en la ventana [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;
}

código java

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;}
}

código pitón

  

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)

Supongo que te gusta

Origin blog.csdn.net/weixin_43914593/article/details/132507378
Recomendado
Clasificación