121. Melhor Momento para Comprar e Vender Ações
Existem três abordagens comuns para resolver este problema:
- Abordagem Gulosa: Manter o menor valor de compra até o dia atual.
- Programação Dinâmica 2D: Utilizar uma matriz para representar estados.
- Prograamção Dinâmica Otimizada: Reduzir para variáveis constantes.
class Solution {
public int maxProfit(int[] prices) {
// Abordagem gulosa:
int menorPreco = prices[0];
int lucroMaximo = 0;
for (int preco : prices) {
menorPreco = Math.min(menorPreco, preco);
lucroMaximo = Math.max(lucroMaximo, preco - menorPreco);
}
return lucroMaximo;
}
}
class Solution {
public int maxProfit(int[] prices) {
int n = prices.length;
// dp[dia][0] = lucro máximo sem ação no final do dia
// dp[dia][1] = lucro máximo com ação no final do dia
int[][] dp = new int[n][2];
dp[0][0] = 0;
dp[0][1] = -prices[0];
for (int i = 1; i < n; i++) {
dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1] + prices[i]);
dp[i][1] = Math.max(dp[i-1][1], -prices[i]);
}
return dp[n-1][0];
}
}
class Solution {
public int maxProfit(int[] prices) {
int semAcao = 0;
int comAcao = Integer.MIN_VALUE;
for (int preco : prices) {
int novoSemAcao = Math.max(semAcao, comAcao + preco);
int novoComAcao = Math.max(comAcao, -preco);
semAcao = novoSemAcao;
comAcao = novoComAcao;
}
return semAcao;
}
}
122. Melhor Momento para Comprar e Vender Ações II
Diferente do problema anterior, aqui é permitido realizar múltiplas transações. A principal diferença na transição de estado é que, ao comprar uma ação, o lucro considera o estado anterior sem ação (que já pode incluir lucros de transações passadas).
class Solution {
public int maxProfit(int[] prices) {
int semAcao = 0;
int comAcao = Integer.MIN_VALUE;
for (int preco : prices) {
int novoSemAcao = Math.max(semAcao, comAcao + preco);
int novoComAcao = Math.max(comAcao, semAcao - preco);
semAcao = novoSemAcao;
comAcao = novoComAcao;
}
return semAcao;
}
}
123. Melhor Momento para Comprar e Vender Ações III
Duas abordagens são possíveis:
- Abordagem Geral com k=2: Adicionar dimensão para o número de transações.
- Abordagem com Estados Explícitos: Definir quatro estados para duas transações.
class Solution {
public int maxProfit(int[] prices) {
int n = prices.length;
// dp[dia][k][0] = lucro sem ação, com até k transações
// dp[dia][k][1] = lucro com ação, com até k transações
int[][][] dp = new int[n][3][2];
for (int k = 1; k <= 2; k++) {
dp[0][k][0] = 0;
dp[0][k][1] = -prices[0];
}
for (int i = 1; i < n; i++) {
for (int k = 1; k <= 2; k++) {
dp[i][k][0] = Math.max(dp[i-1][k][0], dp[i-1][k][1] + prices[i]);
dp[i][k][1] = Math.max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i]);
}
}
return dp[n-1][2][0];
}
}
class Solution {
public int maxProfit(int[] prices) {
int primeiraTransacaoSemAcao = 0;
int primeiraTransacaoComAcao = Integer.MIN_VALUE;
int segundaTransacaoSemAcao = 0;
int segundaTransacaoComAcao = Integer.MIN_VALUE;
for (int preco : prices) {
segundaTransacaoSemAcao = Math.max(segundaTransacaoSemAcao, segundaTransacaoComAcao + preco);
segundaTransacaoComAcao = Math.max(segundaTransacaoComAcao, primeiraTransacaoSemAcao - preco);
primeiraTransacaoSemAcao = Math.max(primeiraTransacaoSemAcao, primeiraTransacaoComAcao + preco);
primeiraTransacaoComAcao = Math.max(primeiraTransacaoComAcao, -preco);
}
return segundaTransacaoSemAcao;
}
}