Introducción

1

Patrones de Arreglos y Strings: Ventana Deslizante y Dos Apuntadores

2

Arrays y Strings: Funcionamiento y Complejidades Temporales

Dos Apuntadores

3

Patrón de Dos Apuntadores en Algoritmos de Lista

4

Verificación de Orden en Diccionario Alienígena

5

Ordenamiento de Palabras en Idiomas Alienígenas

6

Playground: Verifying Alien Dictionary

7

Ordenación de Palabras en Diccionario Alienígena

8

Combinar Listas Ordenadas en un Array Ascendente

9

Ordenamiento de Listas con Complejidad Óptima y Espacio Constante

10

Playground: Merge Two Sorted Lists

11

Intercalación de Listas Ordenadas en Python

12

Resolver el problema "Container with Most Water" en Python

13

Cálculo Óptimo de Área en Listas de Alturas

14

Playground: Container with Most Water

15

Implementación de solución de cálculo de área máxima en Java

16

Implementación de Trapping Rainwater en Complejidad Lineal

17

Retos de Algoritmos con Apuntadores en Python

18

Patrones de Dos Apuntadores: Soluciones a Problemas Comunes en Python

Ventana Deslizante

19

Patrón Ventana Deslizante para Análisis de Datos Secuenciales

20

Subcadena más larga sin caracteres repetidos: patrón ventana deslizante

21

Algoritmo de Ventana Deslizante para Subcadenas Únicas

22

Playground: Longest Substring Without Repeating Characters

23

Algoritmo Python para Substring más Largo Sin Repeticiones

24

Retos de Algoritmos: Dos Apuntadores y Subcadenas

25

Máximos 1s Consecutivos y Subcadenas sin Repeticiones

Búsqueda Binaria

26

Algoritmo de búsqueda binaria en listas ordenadas

27

Búsqueda en Arrays Rotados: Encontrar Entero en Lista Ordenada

28

Búsqueda Binaria en Arreglos Rotados

29

Playground: Search in Rotated Arrays

30

Búsqueda en Arrays Rotados con C++

31

Búsqueda eficiente en matriz ordenada MxN

32

Búsqueda Binaria en Matrices 2D Ordenadas

33

Playground: Search 2D Array Matrix

34

Búsqueda Binaria en Matrices con Python

Próximos pasos

35

Estructuras de Datos Lineales: Conceptos y Aplicaciones

No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Cálculo Óptimo de Área en Listas de Alturas

13/35
Recursos

¿Cómo resolver el problema del área máxima de agua entre alturas?

Enfrentar el problema de calcular la mayor área de agua que puede contenerse entre un conjunto de alturas, representadas por una lista de números, es un ejercicio interesante de lógica y optimización de algoritmos. Aquí exploramos métodos para encontrar soluciones más eficientes que simplemente calcular todas las combinaciones posibles.

¿Cuál sería una solución inicial y su complejidad?

La primera estrategia que podríamos considerar para este problema es calcular todas las áreas posibles formadas por cada par de alturas que se comparan en la lista. Este enfoque implica combinar todas las alturas entre sí para calcular el área, lo cual lleva a una complejidad de tiempo de (O(n^2)), ya que estaríamos comparando cada altura con todas las demás. Aunque es una solución válida, no es la más óptima debido al alto costo computacional.

¿Cómo calcular un área en este problema?

El cálculo del área de agua alojada entre dos alturas puede parecer complicado, pero se simplifica una vez entendemos que el área de un rectángulo es el producto de su base por su altura. En este contexto:

  • Altura: La menor de las dos alturas comparadas. Esto es porque, al llenar agua entre dos paredes de distinta altura, el agua se derramará sobre la pared más baja.
  • Base: La distancia entre los dos índices que representan las alturas en la lista.

Por ejemplo, si la altura mínima es 2 y la distancia es 4, el área sería (2 \times 4 = 8).

¿Cómo optimizar el cálculo para reducir la complejidad?

Para optimizar el cálculo, podemos usar dos apuntadores (P1 y P2), colocados uno al comienzo y otro al final de la lista de alturas. La idea es:

  1. Calcular el área entre las alturas en las posiciones de los apuntadores.
  2. Actualizar la mejor área encontrada si el área calculada es mayor que la almacenada previamente.
  3. Mover los apuntadores hacia el centro:
    • Siempre movemos el apuntador que apunte hacia la menor altura entre los dos extremos comparados. Esto se basa en la lógica de que mover el apuntador del lado menor podría abrir la posibilidad de encontrar un área mayor.

Repetimos estos pasos hasta que los dos apuntadores se encuentren, asegurando que exploramos todas las combinaciones de altura posibles de forma eficiente.

Aquí está un ejemplo en pseudocódigo:

def encontrar_mejor_area(alturas):
    mejor_area = 0
    p1, p2 = 0, len(alturas) - 1
    
    while p1 < p2:
        altura = min(alturas[p1], alturas[p2])
        base = p2 - p1
        area = altura * base
        mejor_area = max(mejor_area, area)
        
        if alturas[p1] < alturas[p2]:
            p1 += 1
        else:
            p2 -= 1
            
    return mejor_area

# Ejemplo de uso
alturas = [1, 8, 6, 2, 5, 4, 8, 3, 7]
print(encontrar_mejor_area(alturas))  # Salida: 49

¿Cuál es la complejidad de la solución optimizada?

Al utilizar el enfoque de dos apuntadores, la complejidad temporal mejora a (O(n)), ya que solo es necesario una pasada por la lista. La complejidad espacial se mantiene en (O(1)) porque solo utilizamos un número constante de variables para almacenar la mejor área encontrada.

Consejos adicionales para optimización

  • Usar TDD (Desarrollo Orientado por Pruebas): Al implementar, prueba casos límite como cuando todas las alturas son iguales o cuando la lista solo contiene dos alturas.
  • Visualizar el problema: Dibujar el problema en papel o utilizar gráficos puede ayudar a entender mejor las operaciones a realizar.
  • Participar en foros: Comprometerse anónimamente o con colegas para discutir diferentes soluciones puede proporcionar nuevas perspectivas y optimizaciones.

Adoptar un enfoque metódico al plantear problemas complejos como este nos prepara para resolver desafíos algorítmicos más fácilmente. ¡Continúa explorando y practicando!

Aportes 20

Preguntas 1

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Se me hacía raro porque la profe había puesto P2 + P1 +1 si la posición por donde la miro me daba 4, posición 7 - posición 3 = 4, no tenia que sumar nada, o si fuera desde el cero seria posición 6 - 2 = 4, en la siguiente clase me dare cuenta que paso con ese +1

Esta es mi solución en Java:

public class ContainerWithMostWaterOptimizado {

    public static int containerWithMostWater(int[] alturas) {
        int mejorArea = 0;
        int p1 = 0;
        int p2 = alturas.length - 1;

        while (p1 != p2) {
            int altura = Math.min(alturas[p1], alturas[p2]);
            int ancho = p2 - p1;
            int area = altura * ancho;

            if (area > mejorArea) {
                mejorArea = area;
            }

            if (alturas[p1] < alturas[p2]) {
                p1++;
            } else {
                p2--;
            }
        }

        return mejorArea;
    }

    public static void main(String[] args) {
        int[] alturas = {1, 8, 6, 2, 5, 4, 8, 3, 7};

        int areaMax = containerWithMostWater(alturas);
        System.out.println(areaMax);
    }
}

La verdad hubiera tardado eones en llegar a una solución O(n) como la profe, esto fue lo que entendi:

Ir calculando el area mas grande posible para el apuntador de menor valor.

Guarda un area global que cambia solo si el area calculada en el paso anterior es mayor, tomando este valor.

El apuntador que tenga menor valor se va a mover hacia el centro ya que no hay posibilidad de conseguir un area mayor, porque la distancia hacia el otro apuntador solo va a disminuir (por ejemplo cuando tenemos el valor 1, si descartaramos el valor 7, la distancia entre apuntadores seria n-2 por tanto el area para ese elemento seria menor que la que ya conseguimos 1(n-1) > 1(n-2)).

Cuando los dos apuntadores estan en la misma posicion se termina el algoritmo.

solucion en swift ```js func maxArea(_ height: [Int]) -> Int { var indexL = 0 var indexR = height.count - 1 var max = 0 while indexR > indexL { var possibleMax = (indexR - indexL) * min(height[indexL], height[indexR]) if possibleMax > max { max = possibleMax } if height[indexL] > height[indexR] { indexR -= 1 } else { indexL += 1 } } return max } ```
Mi solución: ```js def most_water(columns: list[int]) -> int: max_water = 0 for idx1, col1 in enumerate(columns): idx2 = idx1 + 1 while idx2 < len(columns): height = min(col1, columns[idx2]) base = idx2 - idx1 water_volume = height * base if water_volume > max_water: max_water = water_volume idx2 += 1 return max_water ```def most\_water(*columns*: list\[int]) -> int: max\_water = 0 *for* idx1, col1 *in* enumerate(columns): idx2 = idx1 + 1 *while* idx2 < len(columns): height = min(col1, columns\[idx2]) base = idx2 - idx1 water\_volume = height \* base *if* water\_volume > max\_water: max\_water = water\_volume idx2 += 1 *return* max\_water
Esta es mi solucion en java: ```js import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Optional; public class AreaPiscina { public static int calcularMayorArea(int[] numeros){ List<Integer> resultados = new ArrayList<>(); for (int i = 0; i < numeros.length; i++) { for (int j = i + 1; j < numeros.length; j++) { int altura = Math.min(numeros[i], numeros[j]); int ancho = j - i; int resultado = altura * ancho; resultados.add(resultado); } } Optional<Integer> numeroMaximo = resultados.stream().max(Comparator.comparingInt(i -> i.intValue())); return numeroMaximo.orElse(0); } public static void main(String[] args) { int[] numeros = {8,1,6,2,5,4,1,3,7}; System.out.println(AreaPiscina.calcularMayorArea(numeros)); } } ```import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Optional; public class AreaPiscina { public static int calcularMayorArea(int\[] numeros){ List\<Integer> resultados = new ArrayList<>(); for (int i = 0; i < numeros.length; i++) { for (int j = i + 1; j < numeros.length; j++) { int altura = Math.*min*(numeros\[i], numeros\[j]); int ancho = j - i; int resultado = altura \* ancho; resultados.add(resultado); } } Optional\<Integer> numeroMaximo = resultados.stream().max(Comparator.*comparingInt*(i -> i.intValue())); return numeroMaximo.orElse(0); } public static void main(String\[] args) { int\[] numeros = {8,1,6,2,5,4,1,3,7}; System.*out*.println(AreaPiscina.*calcularMayorArea*(numeros)); } }
comparto el código que hice antes de llegar a esta clase, tuve un approach muy distinto, aún no sé si pasará las pruebas de platzi pero por ahora me dio la respuesta de 49 xD ``` const containerWithMostWater = (alturas: number\[]): number => { const alturasCopy = \[...alturas] const biggestNumber = alturasCopy.sort((a,b) => b-a)\[0] const secondBiggestNumberArray = alturasCopy.sort((a,b) => b-a) let secondBiggestNumber = Number.NEGATIVE\_INFINITY for (let index = 0; index < secondBiggestNumberArray.length; index++) { if (secondBiggestNumberArray\[index] < biggestNumber) { secondBiggestNumber = secondBiggestNumberArray\[index] break } } const indexesOfBiggestNumbers: number\[] = \[] for (let index = 0; index < alturas.length; index++) { if (alturas\[index] === biggestNumber) { indexesOfBiggestNumbers.push(index) } } const indexesOfSecondBiggestNumbers: number\[] = \[] for (let index = 0; index < alturas.length; index++) { if (alturas\[index] === secondBiggestNumber) { indexesOfSecondBiggestNumbers.push(index) } } let distance: number = Number.NEGATIVE\_INFINITY const secondBiggestNumberBiggestIndex = indexesOfSecondBiggestNumbers.pop() distance = secondBiggestNumberBiggestIndex! - indexesOfBiggestNumbers\[0] return distance \* secondBiggestNumber} console.log(containerWithMostWater(\[1,8,6,2,5,4,8,3,7]))console.log(containerWithMostWater(\[9,8,8,7,5,4,8,9,3,7,8,8,7,1,1,1,1,1,1,5,4,9])) /\*1. encontrar el número más grande2. encontrar el segundo número más grande3. encontrar la distancia más larga entre estos dos números3.1 ¿guardar los índices de todos los números iguales al más grande?3.2 ¿guardar los índices de todos los números iguales al segundo más grande?3.3 calcular la distancia de los más alejados4. multiplicar el segundo número más grande por la distancia más larga\*/ ```
This one is my solution: ```python def get_container(heights: list): length = len(heights) if length == 0: return None if length < 2: return 0 max_area = 0 i, j = 0, length - 1 while i < j: actual_area = min(heights[i], heights[j]) * (j - i) if actual_area > max_area: max_area = actual_area if heights[i] == heights[j]: j -= 1 i += 1 elif heights[i] < heights[j]: i += 1 else: j -= 1 return max_area ```
esta es mi solucion en dart ![](https://static.platzi.com/media/user_upload/image-f2d6165e-0dd8-4015-ba30-fc405877c4cb.jpg)
```js # Time Complexity: O(n) # Space Complexity: O(1) def water_area_faster(heights) max_area = -Float::INFINITY left = 0 right = heights.length - 1 while left <= right width = right - left left_height = heights[left] right_height = heights[right] height = [left_height, right_height].min area = width * height max_area = [max_area, area].max if left_height < right_height left += 1 next end if left_height > right_height right -= 1 next end if left + 1 == right || right - 1 == left break end if left_height == right_height if heights[left + 1] >= heights[right - 1] left += 1 next else right -= 1 next end end end max_area end ```# Time Complexity: O(n)# Space Complexity: O(1) def water\_area\_faster(heights) max\_area = -Float::INFINITY left = 0 right = heights.length - 1 while left <= right width = right - left left\_height = heights\[left] right\_height = heights\[right] height = \[left\_height, right\_height].min area = width \* height max\_area = \[max\_area, area].max if left\_height < right\_height left += 1 next end if left\_height > right\_height right -= 1 next end if left + 1 == right || right - 1 == left break end if left\_height == right\_height if heights\[left + 1] >= heights\[right - 1] left += 1 next else right -= 1 next end end end max\_areaend ![](https://static.platzi.com/media/user_upload/image-ce44c64a-ba52-4552-bfec-818ec4cd3d2e.jpg)

Mi solucion en typescript:

export const containerWithMostWater = (heights: number[]): number => {
  let water: number = 0;

  let p1: number = 0;
  let p2: number = heights.length - 1;

  while (p2 > p1) {
    let currentWater: number = (p2 - p1) * (heights[p1] < heights[p2] ? heights[p1] : heights[p2]);

    if (currentWater > water) water = currentWater;

    // If values are the same, move the two pointer
    if (heights[p1] === heights[p2]) {
      p1 = p1 + 1; // move pointer #1 to the right
      p2 = p2 - 1; // move pointer #2 to the left;
    } else if (heights[p1] > heights[p2]) {
      p2 = p2 - 1; // move pointer #2 because is the least tall
    } else if (heights[p1] < heights[p2]) {
      p1 = p1 + 1; // move pointer #1 because is the least tall
    }
  }

  return water;
};

Mi implementación en Java

public static int calculateWater(int[] pileNumbers){
    int p1=0;
    int p2=pileNumbers.length-1;
    int p3=0;
    int temp = 0;
    while(p1<p2){
        temp = Math.min(pileNumbers[p1], pileNumbers[p2])*(p2-p1);
        if(p3<temp)
            p3 = temp;
        if(p1<p2){
            p1++;
        }else{
            p2--;
        }
    }
    return p3;
}

comparto mi solucion

function ContainerWithMostWater(list) {
    let result = 0
    let counter1 = 0
    let counter2 = list.length - 1

    const calculateWater = (height1, height2, distance) => {
        if (height1 < height2) return height1 * distance
        return height2 * distance
    }

    for (let index = 0; index < list.length; index++) {
        if (result < calculateWater(list[counter1], list[counter2], counter2 - counter1)) result = calculateWater(list[counter1], list[counter2], counter2 - counter1)
        if (list[counter1] < list[counter2]) counter1++
        else counter2++
    }

    return result
}

La verdad no sé si hay algo que se me está pasando por alto, pero si los dos apuntadores se encuentran en el centro y ahi termina la ejecución, no voy a estar considerando todas las posibilidades: por ejemplo, si el input es [1, 1, 1, 1, 1, 100, 100], nunca voy a calcular el area entre 100 y 100, o sí? expliquenme porfas jajaj. Lo que yo hice es mover un solo apuntador y cuando llegue al otro extremo donde esta el segundo apuntador, volver el primero a 0 y disminuir el segundo y terminar cuando el segundo apuntadort deje de ser mayor a 0. Mi solución en js:

function containerWithMostWater(nums){
let p1 = 0,
p2 = nums.length - 1
resultado = 0

while(0 < p2) {
    if(p1 < p2){
        let altura = Math.min(nums[p2], nums[p1]),
        ancho = nums.slice(p1, p2).length
        area = ancho * altura
        console.log("p2", nums[p2], "p1", nums[p1]);
        console.log("altura", altura, "ancho", ancho, area)
        if(area > resultado){
            resultado = area
        }
        p1++
    } else {
        p1 = 0
        p2--
    }
}

return resultado

}

Mi solución en C++ 😄

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

int containerWithMostWater(int input[],int arraySize);
int calculateArea(int lengt, int width);
int updateVariable(int maxArea, int currentArea);

int main(){
    //Change the values of the array.
    int array1[]= {1, 8, 6, 2, 5, 4, 8, 3, 7};
    //Variable to storage the number of elements inside the array.
    int arraySize= sizeof(array1)/sizeof(array1[0]);
                                                //Calling the Function
    cout << "The Maximum possible area is: " << containerWithMostWater(array1, arraySize) << endl;
    return 0;
}

int containerWithMostWater(int input[], int arraySize){
    //Pointer 1
    int p1= 0;
    //Pointer 2
    int p2= arraySize-1;
    //MaxArea is a variable to save the maximum possible area
    //that a container can storage.
    int maxArea= 0;

    for (int i = 0; i < arraySize; i++)
    {
        //Comparisons to check which pointer has to be updated.
        if(input[p1]<input[p2]){
            maxArea = updateVariable(maxArea, calculateArea(input[p1], p2-p1));
            p1+=1;
        }else if(input[p1]>input[p2]){
            maxArea= updateVariable(maxArea, calculateArea(input[p2], (p2-p1)));
            p2-=1;
        }else{
            //This option is made for the case input[p1]==input[p2].
            maxArea= updateVariable(maxArea, calculateArea(input[p2], (p2-p1)));
            p1+=1;
            p2-=1;
        }
    }
    //Returns the maximum Area.
    return maxArea;
}

int calculateArea(int lengt, int width){
    //Returns the area of a rectangle, which the shape that the container has.
    return lengt*width;
}

int updateVariable(int maxArea, int currentArea){
    //Returns the maximum value between the current calculated area and the maxArea
    //from the previous iteration.
    if(maxArea<currentArea){
        maxArea= currentArea;
    }
    return maxArea;
}

No había entendido este tema, asta este ejercicio, la verdad estas explicaciones visuales de como funcionan las variables y los cálculos que se hacen ayudan demasiado.

Adjunto mi posible solucion

    public static int WithMostWater(int[] hights)
    {

        int left = 0;
        int right = hights.Length - 1;

        int maxAreaFound = 0;

        while (left != right)
        {
            int distance = right - left;
            int min = Math.Min(hights[left], hights[right]);
            int area = distance * min;
            if (area > maxAreaFound) maxAreaFound = area;
            left++;
        }

        return maxAreaFound;
    }

este problema yo lo había echo con python así:

def maxArea(self, height: List[int]) -> int:
        n = len(height)
        left = 0
        right = n-1
        base = n-1
        max_value = 0

        while base > 0:
            if height[left] <= height[right]:
               max_v = base*height[left]
               if max_value < max_v:
                   max_value = max_v
               left += 1
                

            elif height[left] > height[right]:
                max_v = base*height[right]
                if max_value < max_v:
                    max_value = max_v
                right -= 1

            base -= 1

        return max_value

Solución en python (al menos como lo entendí yo)

def biggestCont(arr):
    bi = 0 # index of biggest num. before given position
    maxArea = -1
    for i in range(len(arr)):
        area = min(arr[i],arr[bi])*(i-bi)
        if area > maxArea:
            maxArea = area
        if arr[i] > arr[bi]:
            bi = i
    return maxArea

# T = O(n)
# S = O(1)    

arr = [1,8,6,2,5,4,8,3,7]
print(biggestCont(arr))

Ruby:

def most_water_resolver(hs)
  final_area = 0
  hs.each_with_index do |h, index|
    (index+1...hs.length).each do |j|
      hight = [hs[index], hs[j]].min
      base = j - index
      area = hight*base
      final_area = [final_area, area].max
    end
  end
  final_area
end

p most_water_resolver([1, 8, 6, 2, 5, 4, 8, 3, 7])