problema triple de subarreglo

contenido

1. Problema de subarreglo consecutivo I

2. Problema de triplete de subarreglo II

3. Problema de triplete de subarreglo III


1. Problema de subarreglo consecutivo I

Para el enlace DO:

Longitud del subarreglo más largo en un arreglo desordenado de números positivos cuya suma acumulativa es un valor dado

Tema Descripción:

 Ideas para resolver problemas:

En primer lugar, lo que podemos pensar es enumerar violentamente cada subarreglo para calcular su suma acumulada y luego compararlos uno por uno para obtener el valor máximo.

Código correspondiente:

#include<iostream>
#include<vector>
using namespace std;
int main()
{
    int n ,k;
    cin>>n>>k;
    vector<int>arr(n);
    for(int i=0;i<n;i++)
    {
        cin>>arr[i];
    }
    int N=arr.size();
    int maxLen=0;
    for(int left=0;left<N;left++)//枚举每个位置开头
    {
    
        for(int right=left;right<N;right++)//每个位置结尾
        {
            int sum=0;
            for(int i=left;i<=right;i++)//求[left,right]这一段区间的累加和
            {
                sum+=arr[i];
            }
            if(sum==k)
            {
                maxLen=max(maxLen,right-left+1);//长度为right-left+1;
            }
        }
        
    }
    cout<<maxLen<<endl;
    return 0;
}

Pero lo siento mucho por el tiempo de espera. Si extraemos y generamos la matriz de suma acumulativa sin enumerar y calcular la suma acumulativa, ¿será posible reducir la complejidad del tiempo a O (N ^ 2)?

Código correspondiente:

#include<iostream>
#include<vector>
using namespace std;
int main()
{
    int n ,k;
    cin>>n>>k;
    vector<int>arr(n);
    for(int i=0;i<n;i++)
    {
        cin>>arr[i];
    }
    int N=arr.size();
    vector<int>Sum(N+1);//生成累加和多开一个方便后序计算累加和
    
    for(int i=1;i<=N;i++)
    {
        Sum[i]=Sum[i-1]+arr[i-1];
    }
    int maxLen=0;
    for(int left=0;left<N;left++)//枚举每个位置开头
    {
    
        for(int right=left;right<N;right++)//每个位置结尾
        {
            int sum=Sum[right+1]-Sum[left];//直接获取累加和
            
            if(sum==k)
            {
                maxLen=max(maxLen,right-left+1);//长度为right-left+1;
            }
        }
        
    }
    cout<<maxLen<<endl;
    return 0;
}

Envialo:

Desafortunadamente, todavía se agotó el tiempo de espera 

En este punto notamos que cada elemento de la matriz es mayor que 0. Si seguimos acumulando, entonces la suma acumulada debe estar aumentando Generalmente, podemos pensar en la dirección de la ventana cuando nos encontramos con el problema de la monotonicidad. En primer lugar, podemos definir una ventana [izquierda, derecha] que no retroceda, de modo que no tengamos la complejidad temporal del comportamiento de enumeración O(N), que debería poder pasar. Entonces que pensamos, primero usamos una suma variable para registrar la suma acumulada: correspondiente a tres casos

1. Si la suma acumulada en la ventana es mayor que k en este momento, entonces hacemos un conteo fuera de la ventana

2. Si la suma acumulada en la ventana es igual a k en este momento, podemos optar por dejar que un número entre en la ventana o dejar que un número salga de la ventana.

3. Si la suma acumulada en la ventana es menor que k, deje que la siguiente entre directamente en la ventana, y la ventana quedará entre paréntesis a la derecha. Toma [1, 2, 1, 1] como ejemplo a continuación. La suma acumulada debe ser 3: donde left es el borde izquierdo de la ventana y right es el borde derecho de la ventana.

En este momento, sum=1 es menor que la suma acumulada 3 que queremos, y la derecha se expande a la derecha:

 En este momento, la suma acumulada de la ventana 3 es exactamente la suma acumulada que queremos. En este punto actualizamos la respuesta y ampliamos nuestra derecha a la derecha:

En este punto, la suma acumulada es mayor que 4. En este punto, dejamos que 1 cuente por la ventana.

 En este punto seguimos actualizando la respuesta y la derecha continúa moviéndose hacia la derecha. En este punto, la derecha ha cruzado la línea y la respuesta se actualiza. Tenga en cuenta que si hay 0 en la matriz, cuando son iguales, la derecha debe expandirse hacia la derecha para que la longitud sea más larga.

Código correspondiente:

#include<iostream>
#include<vector>
using namespace std;
int main()
{
    int n ,k;
    cin>>n>>k;
    vector<int>arr(n);
    for(int i=0;i<n;i++)
    {
        cin>>arr[i];
    }
    int left=0;
    int right=0;
    //left和right表示窗口[left,right]
    int Maxlen=0;
    int sum=arr[0];
    

    while(right<arr.size())
    {
        if(sum==k)
        {
            Maxlen=max(Maxlen,right-left+1);
            sum+=arr[++right];
        }
        else if(sum>k)//大了一个数从窗口滑出
        {
            sum-=arr[left++];
        }
        else
        {
            ++right;//窗口向右动
            if(right==arr.size())//如果以及越界了跳出循环
            {
                break;
            }
            sum+=arr[right];//将当前数加上
        }
        
    }
    cout<<Maxlen<<endl;
    return 0;
}

2. Problema de triplete de subarreglo II

Enlace DO correspondiente:

La longitud del subarreglo más largo cuya suma acumulada es un valor dado en un arreglo no ordenado Desarrollar papel

Tema Descripción:

Ideas para resolver problemas:

La diferencia entre esta pregunta y la pregunta anterior es que puede haber números negativos en esta pregunta, por lo que la suma acumulativa no es incremental. En este punto, no podemos usar la ventana para el procesamiento. La forma más fácil es el método anterior, enumerando todos los sub-arreglos y luego juzgándolos uno por uno, pero la complejidad de tiempo de esto es O(N^3) si usamos La complejidad de tiempo de la optimización de la suma de prefijos sigue siendo O (N ^ 2) y aún se agotará el tiempo de espera. Pero la idea de esta pregunta sigue siendo la idea de usar el prefijo suma:

Solo necesitamos definir la suma acumulada de una matriz de registros de la tabla Hash desde la posición 0. La idea es exactamente la misma que la de la suma de dos números. Agregue la suma acumulada en la matriz a la tabla hash a su vez y vaya a la tabla hash cada vez Verifique si hay una suma-k para esta acumulación y actualice la respuesta si la hay. En ese momento, a lo que debemos prestar atención aquí es que debemos agregar un registro map[0]=-1 por adelantado, es decir, la suma acumulada de 0 aparece en la posición -1 como muy pronto. no lo agregue, perderemos la respuesta que comienza con 0 (tenga en cuenta que definimos esto El significado de la tabla hash es que la clave representa la suma acumulativa y el val representa la ocurrencia más temprana). Lo siguiente toma [1,1,1],k=3 como ejemplo:

 En este punto, hemos encontrado el subarreglo con la suma acumulativa de 3. Vamos a la tabla hash para descubrir que no hay una suma acumulativa de 0. En este momento, nos perderemos la respuesta, por lo que debemos agregue la suma acumulada de 0 al hash dentro de la tabla.

 

Código correspondiente:

#include<iostream>
#include<unordered_map>
#include<vector>
using namespace std;
int main()
{
    int n,k;
    cin>>n>>k;
    vector<int>arr(n);
    for(int i=0;i<n;i++)
    {
        cin>>arr[i];
    }
    unordered_map<int,int>Hash;//记录累加和
    int sum=0;
    int maxLen=0;
    Hash[0]=-1;//注意一定要加上这一条记录否则会错过以0开头的答案
    for(int i=0;i<n;i++)
    {
        sum+=arr[i];
        if(Hash.count(sum-k))
        {
            maxLen=max(maxLen,i-Hash[sum-k]);//更新答案
        }
        
        if(!Hash.count(sum))//如果当前的累加和在哈希表里不存在直接加进去
        {
            Hash[sum]=i;
        }
    }
    cout<<maxLen<<endl;
    return 0;
}

Extensión 1:

Enlace DO correspondiente:

Suplemento 1 para la serie de problemas de subarreglo más larga donde la suma acumulativa es el valor dado en un arreglo no ordenado

Tema Descripción:

Ideas para resolver problemas:

Esta pregunta es en realidad una variante de la pregunta anterior, la pregunta anterior busca la longitud del subarreglo más largo cuya suma acumulada es k. Esta pregunta es para encontrar la longitud más larga del subarreglo con el mismo número de números positivos y negativos. Si establecemos el número positivo en 1 y el número negativo en -1, esto no es equivalente a encontrar el subarreglo más largo. cuya suma acumulada es 0. la longitud de la matriz.

 Código correspondiente:

#include<iostream>
#include<unordered_map>
#include<vector>
using namespace std;
int main()
{
    int n;
    cin>>n;
    vector<int>arr(n);
    for(int i=0;i<n;i++)
    {
        cin>>arr[i];
    }
    for(int i=0;i<n;i++)
    {
        if(arr[i]<0)
        {
            arr[i]=-1;
        }
        else if(arr[i]>0)
        {
            arr[i]=1;
        }
    }
    //定义一个哈希表
      int maxlen=0;
    unordered_map<int,int>Hash;
    Hash[0]=-1;
    int sum=0;
    for(int i=0;i<n;i++)
    {
        sum+=arr[i];
        if(Hash.count(sum))
        {
            maxlen=max(maxlen,i-Hash[sum]);
        }
        if(!Hash.count(sum))
        {
            Hash[sum]=i;
        }
    }
    cout<<maxlen;
    
}

Expansión II:

Suplemento 2 para la serie de problemas de subarreglo más larga donde la suma acumulada es el subarreglo más largo de un valor dado en un arreglo no ordenado

Tema Descripción:

 Ideas para resolver problemas:

Esta pregunta es básicamente lo mismo que la pregunta anterior, lo mismo es la reescritura de la pregunta anterior, solo necesitamos cambiar 0 a -1, vuelve a ser la pregunta anterior.

Código correspondiente:

#include<iostream>
#include<unordered_map>
#include<vector>
using namespace std;
int main()
{
    int n;
    cin>>n;
    vector<int>arr(n);
    for(int i=0;i<n;i++)
    {
        cin>>arr[i];
    }
    for(int i=0;i<n;i++)
    {
        if(arr[i]==0)
        {
            arr[i]=-1;
        }
    }
    //定义一个哈希表
      int maxlen=0;
    unordered_map<int,int>Hash;
    Hash[0]=-1;
    int sum=0;
    for(int i=0;i<n;i++)
    {
        sum+=arr[i];
        if(Hash.count(sum))
        {
            maxlen=max(maxlen,i-Hash[sum]);
        }
        if(!Hash.count(sum))
        {
            Hash[sum]=i;
        }
    }
    cout<<maxlen;
    
}

Extensión iii:

560. Sum es un subarreglo de K - LeetCode (leetcode-cn.com)

Tema Descripción:

 

Ideas para resolver problemas:

Esta pregunta y el prototipo son básicamente lo mismo, excepto que el valor inicial que debemos completar es Hash[0]=1; el valor clave es el número de veces de acumulación y ocurrencia. Por favor vea el código para más detalles

Código correspondiente:

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
            unordered_map<int,int>Hash;
            int sum=0;
            int cnt=0;
            Hash[0]=1;//注意一定要加上这个
            for(int i=0;i<nums.size();i++)
            {
                sum+=nums[i];
                cnt+=Hash[sum-k];
                Hash[sum]++;
            }
            return cnt;
    }
};

3. Problema de triplete de subarreglo III

Longitud del subarreglo más largo en un arreglo no ordenado cuya suma acumulada es menor o igual al valor dado

Tema Descripción:

Ideas para resolver problemas:

La idea de resolver este problema es realmente difícil de imaginar, primero es necesario definir una matriz minSum, el significado de minSum[i] se refiere a la suma mínima acumulada que se obtiene a partir de i. La matriz minEnd se refiere al subíndice del final cuando se obtiene la suma mínima acumulada. El proceso de la gran pregunta es el siguiente: definir una variable de suma para registrar la suma acumulada y una variable final para registrar la posición de inicio de la expansión retrasada. Cada vez que comience a expandir la suma hacia la derecha, intente ver si el área de la derecha se puede expandir. Si no se puede expandir, la ventana saldrá un número para intentar ver si se puede expandir. hasta que la ventana no se pueda expandir. Si la ventana no ha contado en este momento, comience a expandirse desde la siguiente posición para ver si puede expandir el área que no se puede expandir.Para obtener más detalles, consulte el código.

#include<iostream>
#include<vector>
using namespace std;
int main(){
   int n,k;
   cin>>n>>k;
    vector<int>arr(n);
    for(int i=0;i<n;i++){
        cin>>arr[i];
    }
    vector<int>minSum(n);//以某一个位置开头往右能取到的最小累加和
    vector<int>minEnd(n);//这个累加和是以谁结尾
    minSum[n-1]=arr[n-1];//以最后一个元素开头的最小累加和就是自己
    minEnd[n-1]=n-1;//结尾位置也是自己
    for(int i=n-2;i>=0;i--){
        if(minSum[i+1]<0){//有利可图
            minSum[i]=arr[i]+minSum[i+1];
            minEnd[i]=minEnd[i+1];
        }
        else{
            minSum[i]=arr[i];
            minEnd[i]=i;
        }
    }
    int end=0;//i是窗口的最右块的最后一个位置,在下一位置,即下一块开始的位置
    int sum=0;
    int ans=0;
    for(int i=0;i<n;i++){
        while(end<n&&sum+minSum[end]<=k){//如果加上后面那一块还没有超过k
            sum+=minSum[end];//将另外一部分吸收进来
            end=minEnd[end]+1;//end始终是迟迟扩不进来的那一块的开头位置
        }      
        //不能在扩了
        ans=max(ans,end-i);//更新答案
        if(end>i){
            sum-=arr[i];//左测一个数出窗口
        }
        else{//说明一上来就扩失败了,此时i即将++所以end跟着i一起走
            end=i+1;
        }
    }
    cout<<ans<<endl;
}

Extensión: dada una matriz arr, dado un valor v, encuentre la longitud de la subarreferencia más larga cuyo valor promedio sea menor o igual que v. Idea para resolver problemas: restar v de cada elemento del arreglo es equivalente a encontrar la longitud del subarreglo más largo cuya suma acumulada de subarreglos es menor o igual a 0, y luego convertirlo al problema anterior

Supongo que te gusta

Origin blog.csdn.net/qq_56999918/article/details/124333442
Recomendado
Clasificación