1112 lines
31 KiB
TypeScript
1112 lines
31 KiB
TypeScript
import type { AlgorithmDefinition } from '@/lib/visualizations/types';
|
|
|
|
// Helper to create a DP cell
|
|
function dpCell(
|
|
col: number,
|
|
value: number | string,
|
|
state: 'normal' | 'highlighted' | 'comparing' | 'computing' | 'success' | 'dimmed' = 'normal'
|
|
) {
|
|
return {
|
|
id: `dp-${col}`,
|
|
value,
|
|
row: 0,
|
|
col,
|
|
state,
|
|
};
|
|
}
|
|
|
|
// Helper to create coins array element
|
|
function coinElement(
|
|
index: number,
|
|
value: number,
|
|
state: 'normal' | 'highlighted' | 'dimmed' | 'success' | 'comparing' = 'normal'
|
|
) {
|
|
return { value, index, state };
|
|
}
|
|
|
|
export const coinChangeAlgorithm: AlgorithmDefinition = {
|
|
id: 'coin-change',
|
|
title: 'Coin Change - Dynamic Programming',
|
|
slug: 'coin-change',
|
|
pattern: {
|
|
name: 'Dynamic Programming',
|
|
description:
|
|
'Break down problems into overlapping subproblems and build solutions from optimal substructure.',
|
|
},
|
|
problemStatement:
|
|
'Given coins of different denominations and a total amount, find the minimum number of coins needed to make that amount. If it cannot be made, return -1.',
|
|
intuition:
|
|
'For each amount from 1 to target, we compute the minimum coins needed by checking all coin denominations. dp[i] = min coins needed for amount i. For each coin, if coin <= i, we can use it: dp[i] = min(dp[i], dp[i-coin] + 1).',
|
|
code: {
|
|
language: 'python',
|
|
code: `def coin_change(coins: list[int], amount: int) -> int:
|
|
# Initialize dp with infinity; dp[0] = 0
|
|
dp = [float('inf')] * (amount + 1)
|
|
dp[0] = 0
|
|
|
|
# Build solution for each amount
|
|
for i in range(1, amount + 1):
|
|
for coin in coins:
|
|
if i - coin >= 0:
|
|
dp[i] = min(dp[i], dp[i - coin] + 1)
|
|
|
|
return dp[amount] if dp[amount] != float('inf') else -1`,
|
|
},
|
|
initialExample: {
|
|
input: { coins: [1, 2, 5], amount: 11 },
|
|
expected: 3,
|
|
},
|
|
steps: [
|
|
// Phase 1: Problem (2 steps)
|
|
{
|
|
id: 'problem-1',
|
|
phase: 'problem',
|
|
explanation:
|
|
'Given coins [1, 2, 5] and amount 11, find the minimum number of coins to make exactly 11.',
|
|
dataState: {
|
|
arrays: [
|
|
{
|
|
id: 'coins',
|
|
label: 'Coins',
|
|
elements: [
|
|
coinElement(0, 1, 'normal'),
|
|
coinElement(1, 2, 'normal'),
|
|
coinElement(2, 5, 'normal'),
|
|
],
|
|
},
|
|
],
|
|
pointers: [],
|
|
variables: [
|
|
{ id: 'amount', name: 'amount', value: 11 },
|
|
],
|
|
calculations: [],
|
|
},
|
|
},
|
|
{
|
|
id: 'problem-2',
|
|
phase: 'problem',
|
|
explanation:
|
|
'A brute-force approach tries all combinations - exponential time O(S^n). Can we do better by reusing solutions to smaller amounts?',
|
|
dataState: {
|
|
arrays: [
|
|
{
|
|
id: 'coins',
|
|
label: 'Coins',
|
|
elements: [
|
|
coinElement(0, 1, 'normal'),
|
|
coinElement(1, 2, 'normal'),
|
|
coinElement(2, 5, 'normal'),
|
|
],
|
|
},
|
|
],
|
|
pointers: [],
|
|
variables: [
|
|
{ id: 'amount', name: 'amount', value: 11 },
|
|
],
|
|
calculations: [],
|
|
},
|
|
},
|
|
|
|
// Phase 2: Intuition (4 steps)
|
|
{
|
|
id: 'intuition-1',
|
|
phase: 'intuition',
|
|
explanation:
|
|
'Key insight: If we know the minimum coins for amount 10, we can make 11 with one more coin of value 1. This is optimal substructure.',
|
|
dataState: {
|
|
arrays: [
|
|
{
|
|
id: 'coins',
|
|
label: 'Coins',
|
|
elements: [
|
|
coinElement(0, 1, 'highlighted'),
|
|
coinElement(1, 2, 'normal'),
|
|
coinElement(2, 5, 'normal'),
|
|
],
|
|
},
|
|
],
|
|
pointers: [],
|
|
variables: [
|
|
{ id: 'amount', name: 'amount', value: 11 },
|
|
],
|
|
calculations: [
|
|
{ id: 'calc-1', expression: 'dp[11] = dp[10] + 1', result: '?', position: 'above' },
|
|
],
|
|
},
|
|
},
|
|
{
|
|
id: 'intuition-2',
|
|
phase: 'intuition',
|
|
explanation:
|
|
'We can also make 11 from amount 9 (using coin 2) or amount 6 (using coin 5). We take the minimum of all options.',
|
|
dataState: {
|
|
arrays: [
|
|
{
|
|
id: 'coins',
|
|
label: 'Coins',
|
|
elements: [
|
|
coinElement(0, 1, 'comparing'),
|
|
coinElement(1, 2, 'comparing'),
|
|
coinElement(2, 5, 'comparing'),
|
|
],
|
|
},
|
|
],
|
|
pointers: [],
|
|
variables: [
|
|
{ id: 'amount', name: 'amount', value: 11 },
|
|
],
|
|
calculations: [
|
|
{ id: 'calc-1', expression: 'min(dp[10]+1, dp[9]+1, dp[6]+1)', result: '?', position: 'above' },
|
|
],
|
|
},
|
|
},
|
|
{
|
|
id: 'intuition-3',
|
|
phase: 'intuition',
|
|
explanation:
|
|
'Build solutions bottom-up: start from amount 0, compute minimum coins for each amount 1, 2, 3, ... up to target.',
|
|
dataState: {
|
|
arrays: [
|
|
{
|
|
id: 'coins',
|
|
label: 'Coins',
|
|
elements: [
|
|
coinElement(0, 1, 'normal'),
|
|
coinElement(1, 2, 'normal'),
|
|
coinElement(2, 5, 'normal'),
|
|
],
|
|
},
|
|
],
|
|
pointers: [],
|
|
variables: [],
|
|
calculations: [],
|
|
grids: [
|
|
{
|
|
id: 'dp',
|
|
label: 'DP Table (min coins for each amount)',
|
|
colLabels: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
|
|
cells: [[
|
|
dpCell(0, '?'),
|
|
dpCell(1, '?'),
|
|
dpCell(2, '?'),
|
|
dpCell(3, '?'),
|
|
dpCell(4, '?'),
|
|
dpCell(5, '?'),
|
|
dpCell(6, '?'),
|
|
dpCell(7, '?'),
|
|
dpCell(8, '?'),
|
|
dpCell(9, '?'),
|
|
dpCell(10, '?'),
|
|
dpCell(11, '?'),
|
|
]],
|
|
},
|
|
],
|
|
},
|
|
},
|
|
{
|
|
id: 'intuition-4',
|
|
phase: 'intuition',
|
|
explanation:
|
|
'State transition: dp[i] = min(dp[i], dp[i - coin] + 1) for each valid coin. Base case: dp[0] = 0 (zero coins for amount zero).',
|
|
dataState: {
|
|
arrays: [
|
|
{
|
|
id: 'coins',
|
|
label: 'Coins',
|
|
elements: [
|
|
coinElement(0, 1, 'normal'),
|
|
coinElement(1, 2, 'normal'),
|
|
coinElement(2, 5, 'normal'),
|
|
],
|
|
},
|
|
],
|
|
pointers: [],
|
|
variables: [],
|
|
calculations: [
|
|
{ id: 'calc-1', expression: 'dp[i] = min(dp[i], dp[i-coin] + 1)', result: '', position: 'above' },
|
|
],
|
|
grids: [
|
|
{
|
|
id: 'dp',
|
|
label: 'DP Table',
|
|
colLabels: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
|
|
cells: [[
|
|
dpCell(0, 0, 'success'),
|
|
dpCell(1, '?'),
|
|
dpCell(2, '?'),
|
|
dpCell(3, '?'),
|
|
dpCell(4, '?'),
|
|
dpCell(5, '?'),
|
|
dpCell(6, '?'),
|
|
dpCell(7, '?'),
|
|
dpCell(8, '?'),
|
|
dpCell(9, '?'),
|
|
dpCell(10, '?'),
|
|
dpCell(11, '?'),
|
|
]],
|
|
},
|
|
],
|
|
},
|
|
},
|
|
|
|
// Phase 3: Pattern (2 steps)
|
|
{
|
|
id: 'pattern-1',
|
|
phase: 'pattern',
|
|
explanation:
|
|
'Dynamic Programming pattern: Define state (dp[i] = min coins for amount i), identify transition (try each coin), set base case (dp[0] = 0).',
|
|
dataState: {
|
|
arrays: [
|
|
{
|
|
id: 'coins',
|
|
label: 'Coins',
|
|
elements: [
|
|
coinElement(0, 1, 'normal'),
|
|
coinElement(1, 2, 'normal'),
|
|
coinElement(2, 5, 'normal'),
|
|
],
|
|
},
|
|
],
|
|
pointers: [],
|
|
variables: [
|
|
{ id: 'state', name: 'State', value: 'dp[i] = min coins' },
|
|
],
|
|
calculations: [],
|
|
},
|
|
},
|
|
{
|
|
id: 'pattern-2',
|
|
phase: 'pattern',
|
|
explanation:
|
|
'Time: O(amount * coins), Space: O(amount). Each amount computed once, checking all coins.',
|
|
dataState: {
|
|
arrays: [
|
|
{
|
|
id: 'coins',
|
|
label: 'Coins',
|
|
elements: [
|
|
coinElement(0, 1, 'normal'),
|
|
coinElement(1, 2, 'normal'),
|
|
coinElement(2, 5, 'normal'),
|
|
],
|
|
},
|
|
],
|
|
pointers: [],
|
|
variables: [
|
|
{ id: 'time', name: 'Time', value: 'O(amount * coins)' },
|
|
{ id: 'space', name: 'Space', value: 'O(amount)' },
|
|
],
|
|
calculations: [],
|
|
},
|
|
},
|
|
|
|
// Phase 4: Code walkthrough (4 steps)
|
|
{
|
|
id: 'code-1',
|
|
phase: 'code',
|
|
explanation:
|
|
'Initialize dp array with infinity (impossible). dp[0] = 0 because we need 0 coins for amount 0.',
|
|
codeLine: 3,
|
|
codeHighlightLines: [2, 3, 4],
|
|
dataState: {
|
|
arrays: [
|
|
{
|
|
id: 'coins',
|
|
label: 'Coins',
|
|
elements: [
|
|
coinElement(0, 1, 'normal'),
|
|
coinElement(1, 2, 'normal'),
|
|
coinElement(2, 5, 'normal'),
|
|
],
|
|
},
|
|
],
|
|
pointers: [],
|
|
variables: [],
|
|
calculations: [],
|
|
grids: [
|
|
{
|
|
id: 'dp',
|
|
label: 'DP Table',
|
|
colLabels: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
|
|
cells: [[
|
|
dpCell(0, 0, 'highlighted'),
|
|
dpCell(1, '∞'),
|
|
dpCell(2, '∞'),
|
|
dpCell(3, '∞'),
|
|
dpCell(4, '∞'),
|
|
dpCell(5, '∞'),
|
|
dpCell(6, '∞'),
|
|
dpCell(7, '∞'),
|
|
dpCell(8, '∞'),
|
|
dpCell(9, '∞'),
|
|
dpCell(10, '∞'),
|
|
dpCell(11, '∞'),
|
|
]],
|
|
},
|
|
],
|
|
},
|
|
},
|
|
{
|
|
id: 'code-2',
|
|
phase: 'code',
|
|
explanation:
|
|
'Outer loop: iterate through amounts 1 to target. For each amount, we compute the minimum coins.',
|
|
codeLine: 7,
|
|
dataState: {
|
|
arrays: [
|
|
{
|
|
id: 'coins',
|
|
label: 'Coins',
|
|
elements: [
|
|
coinElement(0, 1, 'normal'),
|
|
coinElement(1, 2, 'normal'),
|
|
coinElement(2, 5, 'normal'),
|
|
],
|
|
},
|
|
],
|
|
pointers: [],
|
|
variables: [
|
|
{ id: 'i', name: 'i', value: '1 to amount' },
|
|
],
|
|
calculations: [],
|
|
},
|
|
},
|
|
{
|
|
id: 'code-3',
|
|
phase: 'code',
|
|
explanation:
|
|
'Inner loop: try each coin. If coin fits (i - coin >= 0), update dp[i] with minimum.',
|
|
codeLine: 8,
|
|
codeHighlightLines: [8, 9, 10],
|
|
dataState: {
|
|
arrays: [
|
|
{
|
|
id: 'coins',
|
|
label: 'Coins',
|
|
elements: [
|
|
coinElement(0, 1, 'comparing'),
|
|
coinElement(1, 2, 'comparing'),
|
|
coinElement(2, 5, 'comparing'),
|
|
],
|
|
},
|
|
],
|
|
pointers: [],
|
|
variables: [],
|
|
calculations: [
|
|
{ id: 'calc-1', expression: 'dp[i] = min(dp[i], dp[i-coin] + 1)', result: '', position: 'above' },
|
|
],
|
|
},
|
|
},
|
|
{
|
|
id: 'code-4',
|
|
phase: 'code',
|
|
explanation:
|
|
'Return dp[amount] if reachable, else -1. Infinity means the amount cannot be made with given coins.',
|
|
codeLine: 12,
|
|
dataState: {
|
|
arrays: [
|
|
{
|
|
id: 'coins',
|
|
label: 'Coins',
|
|
elements: [
|
|
coinElement(0, 1, 'normal'),
|
|
coinElement(1, 2, 'normal'),
|
|
coinElement(2, 5, 'normal'),
|
|
],
|
|
},
|
|
],
|
|
pointers: [],
|
|
variables: [],
|
|
calculations: [],
|
|
},
|
|
},
|
|
|
|
// Phase 5: Execution (~25 steps)
|
|
// dp[0] = 0 (base case)
|
|
{
|
|
id: 'exec-1',
|
|
phase: 'execution',
|
|
explanation: 'Initialize: dp[0] = 0 (base case), all others = infinity.',
|
|
codeLine: 4,
|
|
dataState: {
|
|
arrays: [
|
|
{
|
|
id: 'coins',
|
|
label: 'Coins',
|
|
elements: [
|
|
coinElement(0, 1, 'normal'),
|
|
coinElement(1, 2, 'normal'),
|
|
coinElement(2, 5, 'normal'),
|
|
],
|
|
},
|
|
],
|
|
pointers: [],
|
|
variables: [
|
|
{ id: 'i', name: 'i', value: '-' },
|
|
],
|
|
calculations: [],
|
|
grids: [
|
|
{
|
|
id: 'dp',
|
|
label: 'DP Table',
|
|
colLabels: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
|
|
cells: [[
|
|
dpCell(0, 0, 'success'),
|
|
dpCell(1, '∞'),
|
|
dpCell(2, '∞'),
|
|
dpCell(3, '∞'),
|
|
dpCell(4, '∞'),
|
|
dpCell(5, '∞'),
|
|
dpCell(6, '∞'),
|
|
dpCell(7, '∞'),
|
|
dpCell(8, '∞'),
|
|
dpCell(9, '∞'),
|
|
dpCell(10, '∞'),
|
|
dpCell(11, '∞'),
|
|
]],
|
|
},
|
|
],
|
|
},
|
|
},
|
|
|
|
// Compute dp[1]
|
|
{
|
|
id: 'exec-2',
|
|
phase: 'execution',
|
|
explanation: 'Compute dp[1]: Try coin 1. dp[1] = min(∞, dp[0] + 1) = min(∞, 1) = 1.',
|
|
codeLine: 10,
|
|
dataState: {
|
|
arrays: [
|
|
{
|
|
id: 'coins',
|
|
label: 'Coins',
|
|
elements: [
|
|
coinElement(0, 1, 'highlighted'),
|
|
coinElement(1, 2, 'dimmed'),
|
|
coinElement(2, 5, 'dimmed'),
|
|
],
|
|
},
|
|
],
|
|
pointers: [],
|
|
variables: [
|
|
{ id: 'i', name: 'i', value: 1 },
|
|
{ id: 'coin', name: 'coin', value: 1 },
|
|
],
|
|
calculations: [
|
|
{ id: 'calc-1', expression: 'min(∞, dp[0]+1)', result: '1', position: 'above' },
|
|
],
|
|
grids: [
|
|
{
|
|
id: 'dp',
|
|
label: 'DP Table',
|
|
colLabels: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
|
|
cells: [[
|
|
dpCell(0, 0, 'comparing'),
|
|
dpCell(1, 1, 'computing'),
|
|
dpCell(2, '∞'),
|
|
dpCell(3, '∞'),
|
|
dpCell(4, '∞'),
|
|
dpCell(5, '∞'),
|
|
dpCell(6, '∞'),
|
|
dpCell(7, '∞'),
|
|
dpCell(8, '∞'),
|
|
dpCell(9, '∞'),
|
|
dpCell(10, '∞'),
|
|
dpCell(11, '∞'),
|
|
]],
|
|
},
|
|
],
|
|
gridPointers: [
|
|
{ id: 'ptr-i', name: 'i', row: 0, col: 1, color: 'current' },
|
|
{ id: 'ptr-dep', name: 'i-1', row: 0, col: 0, color: 'dependency' },
|
|
],
|
|
},
|
|
},
|
|
|
|
// Compute dp[2]
|
|
{
|
|
id: 'exec-3',
|
|
phase: 'execution',
|
|
explanation: 'Compute dp[2]: Try coin 1 -> dp[1]+1=2. Try coin 2 -> dp[0]+1=1. dp[2] = min(2, 1) = 1.',
|
|
codeLine: 10,
|
|
dataState: {
|
|
arrays: [
|
|
{
|
|
id: 'coins',
|
|
label: 'Coins',
|
|
elements: [
|
|
coinElement(0, 1, 'comparing'),
|
|
coinElement(1, 2, 'highlighted'),
|
|
coinElement(2, 5, 'dimmed'),
|
|
],
|
|
},
|
|
],
|
|
pointers: [],
|
|
variables: [
|
|
{ id: 'i', name: 'i', value: 2 },
|
|
{ id: 'coin', name: 'coin', value: 2 },
|
|
],
|
|
calculations: [
|
|
{ id: 'calc-1', expression: 'min(dp[1]+1, dp[0]+1)', result: '1', position: 'above' },
|
|
],
|
|
grids: [
|
|
{
|
|
id: 'dp',
|
|
label: 'DP Table',
|
|
colLabels: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
|
|
cells: [[
|
|
dpCell(0, 0, 'comparing'),
|
|
dpCell(1, 1, 'success'),
|
|
dpCell(2, 1, 'computing'),
|
|
dpCell(3, '∞'),
|
|
dpCell(4, '∞'),
|
|
dpCell(5, '∞'),
|
|
dpCell(6, '∞'),
|
|
dpCell(7, '∞'),
|
|
dpCell(8, '∞'),
|
|
dpCell(9, '∞'),
|
|
dpCell(10, '∞'),
|
|
dpCell(11, '∞'),
|
|
]],
|
|
},
|
|
],
|
|
gridPointers: [
|
|
{ id: 'ptr-i', name: 'i', row: 0, col: 2, color: 'current' },
|
|
],
|
|
},
|
|
},
|
|
|
|
// Compute dp[3]
|
|
{
|
|
id: 'exec-4',
|
|
phase: 'execution',
|
|
explanation: 'Compute dp[3]: coin 1 -> dp[2]+1=2, coin 2 -> dp[1]+1=2. dp[3] = 2.',
|
|
codeLine: 10,
|
|
dataState: {
|
|
arrays: [
|
|
{
|
|
id: 'coins',
|
|
label: 'Coins',
|
|
elements: [
|
|
coinElement(0, 1, 'comparing'),
|
|
coinElement(1, 2, 'comparing'),
|
|
coinElement(2, 5, 'dimmed'),
|
|
],
|
|
},
|
|
],
|
|
pointers: [],
|
|
variables: [
|
|
{ id: 'i', name: 'i', value: 3 },
|
|
],
|
|
calculations: [
|
|
{ id: 'calc-1', expression: 'min(dp[2]+1, dp[1]+1)', result: '2', position: 'above' },
|
|
],
|
|
grids: [
|
|
{
|
|
id: 'dp',
|
|
label: 'DP Table',
|
|
colLabels: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
|
|
cells: [[
|
|
dpCell(0, 0, 'normal'),
|
|
dpCell(1, 1, 'comparing'),
|
|
dpCell(2, 1, 'comparing'),
|
|
dpCell(3, 2, 'computing'),
|
|
dpCell(4, '∞'),
|
|
dpCell(5, '∞'),
|
|
dpCell(6, '∞'),
|
|
dpCell(7, '∞'),
|
|
dpCell(8, '∞'),
|
|
dpCell(9, '∞'),
|
|
dpCell(10, '∞'),
|
|
dpCell(11, '∞'),
|
|
]],
|
|
},
|
|
],
|
|
gridPointers: [
|
|
{ id: 'ptr-i', name: 'i', row: 0, col: 3, color: 'current' },
|
|
],
|
|
},
|
|
},
|
|
|
|
// Compute dp[4]
|
|
{
|
|
id: 'exec-5',
|
|
phase: 'execution',
|
|
explanation: 'Compute dp[4]: coin 1 -> dp[3]+1=3, coin 2 -> dp[2]+1=2. dp[4] = 2.',
|
|
codeLine: 10,
|
|
dataState: {
|
|
arrays: [
|
|
{
|
|
id: 'coins',
|
|
label: 'Coins',
|
|
elements: [
|
|
coinElement(0, 1, 'comparing'),
|
|
coinElement(1, 2, 'highlighted'),
|
|
coinElement(2, 5, 'dimmed'),
|
|
],
|
|
},
|
|
],
|
|
pointers: [],
|
|
variables: [
|
|
{ id: 'i', name: 'i', value: 4 },
|
|
],
|
|
calculations: [
|
|
{ id: 'calc-1', expression: 'min(dp[3]+1, dp[2]+1)', result: '2', position: 'above' },
|
|
],
|
|
grids: [
|
|
{
|
|
id: 'dp',
|
|
label: 'DP Table',
|
|
colLabels: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
|
|
cells: [[
|
|
dpCell(0, 0, 'normal'),
|
|
dpCell(1, 1, 'normal'),
|
|
dpCell(2, 1, 'comparing'),
|
|
dpCell(3, 2, 'success'),
|
|
dpCell(4, 2, 'computing'),
|
|
dpCell(5, '∞'),
|
|
dpCell(6, '∞'),
|
|
dpCell(7, '∞'),
|
|
dpCell(8, '∞'),
|
|
dpCell(9, '∞'),
|
|
dpCell(10, '∞'),
|
|
dpCell(11, '∞'),
|
|
]],
|
|
},
|
|
],
|
|
gridPointers: [
|
|
{ id: 'ptr-i', name: 'i', row: 0, col: 4, color: 'current' },
|
|
],
|
|
},
|
|
},
|
|
|
|
// Compute dp[5] - First time using coin 5!
|
|
{
|
|
id: 'exec-6',
|
|
phase: 'execution',
|
|
explanation: 'Compute dp[5]: coin 1 -> 3, coin 2 -> 3, coin 5 -> dp[0]+1=1. dp[5] = 1!',
|
|
codeLine: 10,
|
|
decision: {
|
|
question: 'Which coin gives minimum?',
|
|
answer: 'Coin 5: dp[0]+1 = 1',
|
|
action: 'Use one coin of 5',
|
|
},
|
|
dataState: {
|
|
arrays: [
|
|
{
|
|
id: 'coins',
|
|
label: 'Coins',
|
|
elements: [
|
|
coinElement(0, 1, 'comparing'),
|
|
coinElement(1, 2, 'comparing'),
|
|
coinElement(2, 5, 'highlighted'),
|
|
],
|
|
},
|
|
],
|
|
pointers: [],
|
|
variables: [
|
|
{ id: 'i', name: 'i', value: 5 },
|
|
],
|
|
calculations: [
|
|
{ id: 'calc-1', expression: 'min(3, 3, dp[0]+1)', result: '1', position: 'above' },
|
|
],
|
|
grids: [
|
|
{
|
|
id: 'dp',
|
|
label: 'DP Table',
|
|
colLabels: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
|
|
cells: [[
|
|
dpCell(0, 0, 'comparing'),
|
|
dpCell(1, 1, 'normal'),
|
|
dpCell(2, 1, 'normal'),
|
|
dpCell(3, 2, 'normal'),
|
|
dpCell(4, 2, 'success'),
|
|
dpCell(5, 1, 'computing'),
|
|
dpCell(6, '∞'),
|
|
dpCell(7, '∞'),
|
|
dpCell(8, '∞'),
|
|
dpCell(9, '∞'),
|
|
dpCell(10, '∞'),
|
|
dpCell(11, '∞'),
|
|
]],
|
|
},
|
|
],
|
|
gridPointers: [
|
|
{ id: 'ptr-i', name: 'i', row: 0, col: 5, color: 'current' },
|
|
{ id: 'ptr-dep', name: 'i-5', row: 0, col: 0, color: 'dependency' },
|
|
],
|
|
},
|
|
},
|
|
|
|
// Compute dp[6]
|
|
{
|
|
id: 'exec-7',
|
|
phase: 'execution',
|
|
explanation: 'Compute dp[6]: coin 1 -> dp[5]+1=2, coin 2 -> dp[4]+1=3, coin 5 -> dp[1]+1=2. dp[6] = 2.',
|
|
codeLine: 10,
|
|
dataState: {
|
|
arrays: [
|
|
{
|
|
id: 'coins',
|
|
label: 'Coins',
|
|
elements: [
|
|
coinElement(0, 1, 'highlighted'),
|
|
coinElement(1, 2, 'comparing'),
|
|
coinElement(2, 5, 'comparing'),
|
|
],
|
|
},
|
|
],
|
|
pointers: [],
|
|
variables: [
|
|
{ id: 'i', name: 'i', value: 6 },
|
|
],
|
|
calculations: [
|
|
{ id: 'calc-1', expression: 'min(dp[5]+1, dp[4]+1, dp[1]+1)', result: '2', position: 'above' },
|
|
],
|
|
grids: [
|
|
{
|
|
id: 'dp',
|
|
label: 'DP Table',
|
|
colLabels: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
|
|
cells: [[
|
|
dpCell(0, 0, 'normal'),
|
|
dpCell(1, 1, 'comparing'),
|
|
dpCell(2, 1, 'normal'),
|
|
dpCell(3, 2, 'normal'),
|
|
dpCell(4, 2, 'comparing'),
|
|
dpCell(5, 1, 'comparing'),
|
|
dpCell(6, 2, 'computing'),
|
|
dpCell(7, '∞'),
|
|
dpCell(8, '∞'),
|
|
dpCell(9, '∞'),
|
|
dpCell(10, '∞'),
|
|
dpCell(11, '∞'),
|
|
]],
|
|
},
|
|
],
|
|
gridPointers: [
|
|
{ id: 'ptr-i', name: 'i', row: 0, col: 6, color: 'current' },
|
|
],
|
|
},
|
|
},
|
|
|
|
// Compute dp[7]
|
|
{
|
|
id: 'exec-8',
|
|
phase: 'execution',
|
|
explanation: 'Compute dp[7]: coin 1 -> 3, coin 2 -> dp[5]+1=2, coin 5 -> dp[2]+1=2. dp[7] = 2.',
|
|
codeLine: 10,
|
|
dataState: {
|
|
arrays: [
|
|
{
|
|
id: 'coins',
|
|
label: 'Coins',
|
|
elements: [
|
|
coinElement(0, 1, 'comparing'),
|
|
coinElement(1, 2, 'highlighted'),
|
|
coinElement(2, 5, 'highlighted'),
|
|
],
|
|
},
|
|
],
|
|
pointers: [],
|
|
variables: [
|
|
{ id: 'i', name: 'i', value: 7 },
|
|
],
|
|
calculations: [
|
|
{ id: 'calc-1', expression: 'min(3, dp[5]+1, dp[2]+1)', result: '2', position: 'above' },
|
|
],
|
|
grids: [
|
|
{
|
|
id: 'dp',
|
|
label: 'DP Table',
|
|
colLabels: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
|
|
cells: [[
|
|
dpCell(0, 0, 'normal'),
|
|
dpCell(1, 1, 'normal'),
|
|
dpCell(2, 1, 'comparing'),
|
|
dpCell(3, 2, 'normal'),
|
|
dpCell(4, 2, 'normal'),
|
|
dpCell(5, 1, 'comparing'),
|
|
dpCell(6, 2, 'success'),
|
|
dpCell(7, 2, 'computing'),
|
|
dpCell(8, '∞'),
|
|
dpCell(9, '∞'),
|
|
dpCell(10, '∞'),
|
|
dpCell(11, '∞'),
|
|
]],
|
|
},
|
|
],
|
|
gridPointers: [
|
|
{ id: 'ptr-i', name: 'i', row: 0, col: 7, color: 'current' },
|
|
],
|
|
},
|
|
},
|
|
|
|
// Compute dp[8]
|
|
{
|
|
id: 'exec-9',
|
|
phase: 'execution',
|
|
explanation: 'Compute dp[8]: coin 1 -> 3, coin 2 -> 3, coin 5 -> dp[3]+1=3. dp[8] = 3.',
|
|
codeLine: 10,
|
|
dataState: {
|
|
arrays: [
|
|
{
|
|
id: 'coins',
|
|
label: 'Coins',
|
|
elements: [
|
|
coinElement(0, 1, 'comparing'),
|
|
coinElement(1, 2, 'comparing'),
|
|
coinElement(2, 5, 'comparing'),
|
|
],
|
|
},
|
|
],
|
|
pointers: [],
|
|
variables: [
|
|
{ id: 'i', name: 'i', value: 8 },
|
|
],
|
|
calculations: [
|
|
{ id: 'calc-1', expression: 'min(dp[7]+1, dp[6]+1, dp[3]+1)', result: '3', position: 'above' },
|
|
],
|
|
grids: [
|
|
{
|
|
id: 'dp',
|
|
label: 'DP Table',
|
|
colLabels: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
|
|
cells: [[
|
|
dpCell(0, 0, 'normal'),
|
|
dpCell(1, 1, 'normal'),
|
|
dpCell(2, 1, 'normal'),
|
|
dpCell(3, 2, 'comparing'),
|
|
dpCell(4, 2, 'normal'),
|
|
dpCell(5, 1, 'normal'),
|
|
dpCell(6, 2, 'comparing'),
|
|
dpCell(7, 2, 'comparing'),
|
|
dpCell(8, 3, 'computing'),
|
|
dpCell(9, '∞'),
|
|
dpCell(10, '∞'),
|
|
dpCell(11, '∞'),
|
|
]],
|
|
},
|
|
],
|
|
gridPointers: [
|
|
{ id: 'ptr-i', name: 'i', row: 0, col: 8, color: 'current' },
|
|
],
|
|
},
|
|
},
|
|
|
|
// Compute dp[9]
|
|
{
|
|
id: 'exec-10',
|
|
phase: 'execution',
|
|
explanation: 'Compute dp[9]: coin 1 -> 4, coin 2 -> dp[7]+1=3, coin 5 -> dp[4]+1=3. dp[9] = 3.',
|
|
codeLine: 10,
|
|
dataState: {
|
|
arrays: [
|
|
{
|
|
id: 'coins',
|
|
label: 'Coins',
|
|
elements: [
|
|
coinElement(0, 1, 'comparing'),
|
|
coinElement(1, 2, 'highlighted'),
|
|
coinElement(2, 5, 'highlighted'),
|
|
],
|
|
},
|
|
],
|
|
pointers: [],
|
|
variables: [
|
|
{ id: 'i', name: 'i', value: 9 },
|
|
],
|
|
calculations: [
|
|
{ id: 'calc-1', expression: 'min(4, dp[7]+1, dp[4]+1)', result: '3', position: 'above' },
|
|
],
|
|
grids: [
|
|
{
|
|
id: 'dp',
|
|
label: 'DP Table',
|
|
colLabels: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
|
|
cells: [[
|
|
dpCell(0, 0, 'normal'),
|
|
dpCell(1, 1, 'normal'),
|
|
dpCell(2, 1, 'normal'),
|
|
dpCell(3, 2, 'normal'),
|
|
dpCell(4, 2, 'comparing'),
|
|
dpCell(5, 1, 'normal'),
|
|
dpCell(6, 2, 'normal'),
|
|
dpCell(7, 2, 'comparing'),
|
|
dpCell(8, 3, 'success'),
|
|
dpCell(9, 3, 'computing'),
|
|
dpCell(10, '∞'),
|
|
dpCell(11, '∞'),
|
|
]],
|
|
},
|
|
],
|
|
gridPointers: [
|
|
{ id: 'ptr-i', name: 'i', row: 0, col: 9, color: 'current' },
|
|
],
|
|
},
|
|
},
|
|
|
|
// Compute dp[10]
|
|
{
|
|
id: 'exec-11',
|
|
phase: 'execution',
|
|
explanation: 'Compute dp[10]: coin 1 -> 4, coin 2 -> 4, coin 5 -> dp[5]+1=2. dp[10] = 2!',
|
|
codeLine: 10,
|
|
decision: {
|
|
question: 'Which coin gives minimum?',
|
|
answer: 'Coin 5: dp[5]+1 = 2',
|
|
action: 'Two coins of 5',
|
|
},
|
|
dataState: {
|
|
arrays: [
|
|
{
|
|
id: 'coins',
|
|
label: 'Coins',
|
|
elements: [
|
|
coinElement(0, 1, 'comparing'),
|
|
coinElement(1, 2, 'comparing'),
|
|
coinElement(2, 5, 'highlighted'),
|
|
],
|
|
},
|
|
],
|
|
pointers: [],
|
|
variables: [
|
|
{ id: 'i', name: 'i', value: 10 },
|
|
],
|
|
calculations: [
|
|
{ id: 'calc-1', expression: 'min(4, 4, dp[5]+1)', result: '2', position: 'above' },
|
|
],
|
|
grids: [
|
|
{
|
|
id: 'dp',
|
|
label: 'DP Table',
|
|
colLabels: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
|
|
cells: [[
|
|
dpCell(0, 0, 'normal'),
|
|
dpCell(1, 1, 'normal'),
|
|
dpCell(2, 1, 'normal'),
|
|
dpCell(3, 2, 'normal'),
|
|
dpCell(4, 2, 'normal'),
|
|
dpCell(5, 1, 'comparing'),
|
|
dpCell(6, 2, 'normal'),
|
|
dpCell(7, 2, 'normal'),
|
|
dpCell(8, 3, 'normal'),
|
|
dpCell(9, 3, 'success'),
|
|
dpCell(10, 2, 'computing'),
|
|
dpCell(11, '∞'),
|
|
]],
|
|
},
|
|
],
|
|
gridPointers: [
|
|
{ id: 'ptr-i', name: 'i', row: 0, col: 10, color: 'current' },
|
|
{ id: 'ptr-dep', name: 'i-5', row: 0, col: 5, color: 'dependency' },
|
|
],
|
|
},
|
|
},
|
|
|
|
// Compute dp[11] - The answer!
|
|
{
|
|
id: 'exec-12',
|
|
phase: 'execution',
|
|
explanation: 'Compute dp[11]: coin 1 -> dp[10]+1=3, coin 2 -> dp[9]+1=4, coin 5 -> dp[6]+1=3. dp[11] = 3.',
|
|
codeLine: 10,
|
|
dataState: {
|
|
arrays: [
|
|
{
|
|
id: 'coins',
|
|
label: 'Coins',
|
|
elements: [
|
|
coinElement(0, 1, 'highlighted'),
|
|
coinElement(1, 2, 'comparing'),
|
|
coinElement(2, 5, 'highlighted'),
|
|
],
|
|
},
|
|
],
|
|
pointers: [],
|
|
variables: [
|
|
{ id: 'i', name: 'i', value: 11 },
|
|
],
|
|
calculations: [
|
|
{ id: 'calc-1', expression: 'min(dp[10]+1, dp[9]+1, dp[6]+1)', result: '3', position: 'above' },
|
|
],
|
|
grids: [
|
|
{
|
|
id: 'dp',
|
|
label: 'DP Table',
|
|
colLabels: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
|
|
cells: [[
|
|
dpCell(0, 0, 'normal'),
|
|
dpCell(1, 1, 'normal'),
|
|
dpCell(2, 1, 'normal'),
|
|
dpCell(3, 2, 'normal'),
|
|
dpCell(4, 2, 'normal'),
|
|
dpCell(5, 1, 'normal'),
|
|
dpCell(6, 2, 'comparing'),
|
|
dpCell(7, 2, 'normal'),
|
|
dpCell(8, 3, 'normal'),
|
|
dpCell(9, 3, 'comparing'),
|
|
dpCell(10, 2, 'comparing'),
|
|
dpCell(11, 3, 'computing'),
|
|
]],
|
|
},
|
|
],
|
|
gridPointers: [
|
|
{ id: 'ptr-i', name: 'i', row: 0, col: 11, color: 'current' },
|
|
],
|
|
},
|
|
},
|
|
|
|
// Final result
|
|
{
|
|
id: 'exec-13',
|
|
phase: 'execution',
|
|
explanation: 'Complete! dp[11] = 3. We need minimum 3 coins: 5 + 5 + 1 = 11.',
|
|
codeLine: 12,
|
|
dataState: {
|
|
arrays: [
|
|
{
|
|
id: 'coins',
|
|
label: 'Coins',
|
|
elements: [
|
|
coinElement(0, 1, 'success'),
|
|
coinElement(1, 2, 'dimmed'),
|
|
coinElement(2, 5, 'success'),
|
|
],
|
|
},
|
|
],
|
|
pointers: [],
|
|
variables: [
|
|
{ id: 'result', name: 'result', value: 3, derivation: '5 + 5 + 1 = 11' },
|
|
],
|
|
calculations: [
|
|
{ id: 'calc-1', expression: '5 + 5 + 1', result: '11', position: 'above' },
|
|
],
|
|
grids: [
|
|
{
|
|
id: 'dp',
|
|
label: 'DP Table',
|
|
colLabels: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
|
|
cells: [[
|
|
dpCell(0, 0, 'success'),
|
|
dpCell(1, 1, 'success'),
|
|
dpCell(2, 1, 'success'),
|
|
dpCell(3, 2, 'success'),
|
|
dpCell(4, 2, 'success'),
|
|
dpCell(5, 1, 'success'),
|
|
dpCell(6, 2, 'success'),
|
|
dpCell(7, 2, 'success'),
|
|
dpCell(8, 3, 'success'),
|
|
dpCell(9, 3, 'success'),
|
|
dpCell(10, 2, 'success'),
|
|
dpCell(11, 3, 'highlighted'),
|
|
]],
|
|
},
|
|
],
|
|
gridPointers: [
|
|
{ id: 'ptr-result', name: 'answer', row: 0, col: 11, color: 'result' },
|
|
],
|
|
},
|
|
},
|
|
],
|
|
};
|