Resolvendo Problemas Clássicos e Explorando Programação Dinâmica com JavaScript

Resolvendo Problemas Clássicos e Explorando Programação Dinâmica com JavaScript

Programar é uma atividade cheia de desafios. Neste artigo vamos explorar problemas clássicos e programação dinâmica, utilizando exemplos práticos em JavaScript. 

Quais os problemas que serão abordados neste artigo?

  • Torre de Hanói
  • Dois Números com Soma Alvo
  • Elemento Mais Frequente de um Array
  • O Problema da Mochila
  • Maior Subsequência Crescente
  • Fibonacci Otimizado

 

 

A Torre de Hanói

 

A Torre de Hanói é um quebra-cabeça matemático que foi criado em 1883 pelo matemático francês Édouard Lucas. Ele apresentou o problema sob o nome "Torre de Brâmanes" e o associou a uma lenda fascinante para torná-lo mais intrigante.

Segundo a lenda, havia um templo em Benares (atualmente Varanasi, na Índia), onde sacerdotes realizavam um ritual envolvendo três pinos e 64 discos de ouro de tamanhos diferentes. A tarefa dos sacerdotes era mover todos os discos de um pino para outro, seguindo as mesmas regras do quebra-cabeça moderno:

 

- Apenas um disco pode ser movido por vez.

- Um disco maior não pode ser colocado sobre um menor.

- Todos os discos devem ser transferidos de uma torre para outra.

 

Dizia-se que quando os sacerdotes completassem a tarefa, o universo chegaria ao fim. No entanto, a matemática por trás do problema mostra que isso levaria uma quantidade de tempo extraordinária para acontecer. Mesmo que os sacerdotes trabalhassem a uma velocidade de um movimento por segundo, levariam cerca de 585 bilhões de anos para concluir a tarefa — muito mais do que a idade atual do universo!

Este problema é excelente para entender conceitos de recursão.

 

function hanoi(n, from, to, aux) {

    if (n === 1) {

        console.log(`Move o disco 1 de ${from} para ${to}`);

        return;

    }

    hanoi(n - 1, from, aux, to);

    console.log(`Move o disco ${n} de ${from} para ${to}`);

    hanoi(n - 1, aux, to, from);

}

hanoi(3, \'A\', \'C\', \'B\'); // Exemplo com 3 discos

 

Esse problema ajuda a entender como dividir uma tarefa complexa em subtarefas menores, um conceito crucial em algoritmos.

 

Dois Números com Soma Alvo

 

Dado um array de números e um valor alvo, o objetivo é encontrar dois números cuja soma seja igual ao valor alvo.

 

function twoSum(nums, target) {

    const map = new Map();

    for (let i = 0; i < nums.length; i++) {

        const complement = target - nums[i];

        if (map.has(complement)) {

            return [map.get(complement), i];

        }

        map.set(nums[i], i);

    }

    return [];

}

console.log(twoSum([2, 7, 11, 15], 9)); // Saída: [0, 1]

 

Esse é um problema comum em entrevistas e destaca a eficiência de usar estruturas de dados como Map para resolver problemas em tempo linear.

 

Elemento Mais Frequente

 

O desafio é encontrar o elemento que aparece mais vezes em um array.

 

function mostFrequent(nums) {

    const freqMap = {};

    let maxCount = 0, mostFrequentNum = null;

 

    for (let num of nums) {

        freqMap[num] = (freqMap[num] || 0) + 1;

        if (freqMap[num] > maxCount) {

            maxCount = freqMap[num];

            mostFrequentNum = num;

        }

    }

    return mostFrequentNum;

}

console.log(mostFrequent([1, 3, 2, 3, 3, 1, 2, 1, 1])); // Saída: 1

 

Esse problema introduz o uso de mapas de frequência, uma técnica comum para analisar conjuntos de dados.

 

O problema da mochila

 

O problema da mochila foi formalizado no campo da teoria da computação e da pesquisa operacional. Ele apareceu inicialmente em estudos matemáticos sobre programação linear e teoria dos grafos no início do século XX, mas se popularizou no século XX com a crescente demanda por algoritmos eficientes para resolver problemas reais.

A primeira referência clara ao problema como o conhecemos hoje é encontrada nos trabalhos de pesquisadores como George Dantzig, que também é famoso por desenvolver o método Simplex.

A ideia básica é simples: você é um aventureiro com uma mochila de capacidade limitada. Diante de você estão vários itens, cada um com um peso e um valor. O desafio é escolher quais itens levar para maximizar o valor total sem ultrapassar o peso máximo que a mochila pode suportar.

Este problema é um clássico para aprender sobre otimização e ele é uma metáfora para muitas decisões práticas, como Gestão de Recursos, Planejamento de Investimentos, Logística e Jogos e Simulações.

 

function knapsack(values, weights, capacity) {

    const n = values.length;

    const dp = Array.from({ length: n + 1 }, () => Array(capacity + 1).fill(0));

 

    for (let i = 1; i <= n; i++) {

        for (let w = 1; w <= capacity; w++) {

            if (weights[i - 1] <= w) {

                dp[i][w] = Math.max(dp[i - 1][w], values[i - 1] + dp[i - 1][w - weights[i - 1]]);

            } else {

                dp[i][w] = dp[i - 1][w];

            }

        }

    }

    return dp[n][capacity];

}

console.log(knapsack([60, 100, 120], [10, 20, 30], 50)); // Saída: 220

 

Este problema ensina como usar tabelas para armazenar soluções intermediárias, um conceito essencial na programação dinâmica.

 

Maior Subsequência Crescente

 

O objetivo deste problema é encontrar a maior subsequência crescente dentro de um array de números.

 

 

function longestIncreasingSubsequence(nums) {

    const dp = Array(nums.length).fill(1);

 

    for (let i = 1; i < nums.length; i++) {

        for (let j = 0; j < i; j++) {

            if (nums[i] > nums[j]) {

                dp[i] = Math.max(dp[i], dp[j] + 1);

            }

        }

    }

    return Math.max(...dp);

}

console.log(longestIncreasingSubsequence([10, 9, 2, 5, 3, 7, 101, 18])); // Saída: 4

 

Esse problema mostra como identificar relações entre elementos e usar técnicas iterativas para resolvê-lo eficientemente.

 

Fibonacci Otimizado

 

A sequência de Fibonacci foi introduzida ao mundo ocidental pelo matemático italiano Leonardo de Pisa, conhecido como Fibonacci, em seu livro Liber Abaci (1202). No livro, ele usou a sequência para resolver um problema sobre o crescimento de uma população de coelhos em condições ideais.

Imagine que:

- Você começa com um par de coelhos.

- Cada par de coelhos atinge a maturidade em um mês.

- Após o primeiro mês, cada par maduro gera um novo par de coelhos a cada mês.

- Nenhum coelho morre.

- Quantos pares de coelhos existirão após um determinado número de meses?

Ao modelar o crescimento, Fibonacci descobriu a sequência que leva seu nome.

O desafio é calcular o n-ésimo número de Fibonacci de forma eficiente, evitando a recursão simples.

 

function fibonacci(n) {

    if (n <= 1) return n;

    let prev = 0, curr = 1;

 

    for (let i = 2; i <= n; i++) {

        [prev, curr] = [curr, prev + curr];

    }

    return curr;

}

console.log(fibonacci(10)); // Saída: 55

 

O problema de Fibonacci demonstra como otimizar soluções ao reduzir o uso de memória sem comprometer a eficiência.

 

 

Está começando e deseja saber o que precisa estudar de HTML e JavaScript? Não deixe de conferir os roteiros de estudo de HTML e JavaScript!. São dezenas de conteúdos para você melhorar suas habilidades.

Roteiro de estudos - HTML e CSS

Roteiro de estudos - Javascript

 

Outros conteudos que podem ser de seu interesse

Guia dos principais comandos do GIT
01/05/2022JAVASCRIPT

Guia dos principais comandos do GIT

Tudo o que você precisa conhecer sobre o GIT

Saiba mais...
Monitorando arquivos com NodeJS
15/12/2019JAVASCRIPT

Monitorando arquivos com NodeJS

Veja como controlar alterações de arquivos numa pasta utilizando NodeJS

Saiba mais...

Conteúdo sobre banco de dados sem complicação!