diff --git a/src/algorithms/Recursion/SubsetSum.js b/src/algorithms/Recursion/SubsetSum.js
new file mode 100644
index 0000000..a235f79
--- /dev/null
+++ b/src/algorithms/Recursion/SubsetSum.js
@@ -0,0 +1,118 @@
+export function getSubsetSumSteps(arr = [], target = 0) {
+ const n = arr.length;
+ const steps = [];
+
+ const dp = Array.from({ length: n + 1 }, () =>
+ Array(target + 1).fill(false)
+ );
+
+ dp[0][0] = true;
+
+ steps.push({
+ type: "init",
+ message: "Initialize DP table: dp[0][0] = true (empty subset → sum 0)",
+ dp: structuredClone(dp),
+ });
+
+ for (let i = 1; i <= n; i++) {
+ const val = arr[i - 1];
+
+ steps.push({
+ type: "init_row",
+ row: i,
+ value: val,
+ message: `Processing element arr[${i - 1}] = ${val}`,
+ dp: structuredClone(dp),
+ });
+
+ for (let sum = 0; sum <= target; sum++) {
+ steps.push({
+ type: "process_cell",
+ i,
+ sum,
+ value: val,
+ message: `Checking if we can form sum ${sum} using first ${i} elements`,
+ dp: structuredClone(dp),
+ });
+
+ if (dp[i - 1][sum]) {
+ dp[i][sum] = true;
+ steps.push({
+ type: "true_set",
+ i,
+ sum,
+ by: "exclude",
+ message: `dp[${i}][${sum}] = true (exclude ${val})`,
+ dp: structuredClone(dp),
+ });
+ }
+
+ if (sum >= val && dp[i - 1][sum - val]) {
+ dp[i][sum] = true;
+ steps.push({
+ type: "true_set",
+ i,
+ sum,
+ by: "include",
+ message: `dp[${i}][${sum}] = true (include ${val})`,
+ dp: structuredClone(dp),
+ });
+ }
+ }
+
+ steps.push({
+ type: "complete_row",
+ row: i,
+ message: `Completed row ${i} (processed arr[${i - 1}] = ${val})`,
+ dp: structuredClone(dp),
+ });
+ }
+
+ const isPossible = dp[n][target];
+
+ if (!isPossible) {
+ steps.push({
+ type: "no_solution",
+ message: `No subset found that adds up to target ${target}.`,
+ dp: structuredClone(dp),
+ });
+ return { steps, solutions: [], solutionCount: 0 };
+ }
+
+ const solution = [];
+ let i = n, sum = target;
+
+ while (i > 0 && sum >= 0) {
+ if (dp[i - 1][sum]) {
+ steps.push({
+ type: "decision",
+ message: `arr[${i - 1}] = ${arr[i - 1]} was EXCLUDED`,
+ dp: structuredClone(dp),
+ });
+ i--;
+ } else {
+ const val = arr[i - 1];
+ solution.push(val);
+ steps.push({
+ type: "decision",
+ message: `arr[${i - 1}] = ${val} was INCLUDED`,
+ dp: structuredClone(dp),
+ });
+ sum -= val;
+ i--;
+ }
+ }
+
+ steps.push({
+ type: "solution",
+ solution: solution.reverse(),
+ message: `✅ Found solution subset: [${solution.join(", ")}]`,
+ dp: structuredClone(dp),
+ });
+
+ return {
+ steps,
+ solutions: [solution],
+ solutionCount: 1,
+ };
+}
diff --git a/src/components/Recursion/SubsetSumVisualizer.jsx b/src/components/Recursion/SubsetSumVisualizer.jsx
new file mode 100644
index 0000000..b197f17
--- /dev/null
+++ b/src/components/Recursion/SubsetSumVisualizer.jsx
@@ -0,0 +1,263 @@
+import React, { useEffect, useRef, useState } from "react";
+import { getSubsetSumSteps } from "../../algorithms/Recursion/SubsetSum";
+
+const MIN_SPEED = 50;
+const MAX_SPEED = 2000;
+
+const Color = ({ color, text }) => (
+
+);
+
+export default function SubsetSumVisualizer() {
+ const [inputArray, setInputArray] = useState("3, 34, 4, 12, 5, 2");
+ const [arr, setArr] = useState([3, 34, 4, 12, 5, 2]);
+ const [target, setTarget] = useState(9);
+
+ const [steps, setSteps] = useState([]);
+ const [idx, setIdx] = useState(0);
+ const [playing, setPlaying] = useState(false);
+ const [solutions, setSolutions] = useState([]);
+
+ const [speed, setSpeed] = useState(400);
+ const timerRef = useRef(null);
+
+ const parseArray = () => {
+ const parsed = inputArray
+ .split(",")
+ .map((s) => Number(s.trim()))
+ .filter((n) => !isNaN(n));
+
+ return parsed.length ? parsed : null;
+ };
+
+ const regenerate = () => {
+ const res = getSubsetSumSteps(arr, target);
+ setSteps(res.steps);
+ setSolutions(res.solutions);
+ setIdx(0);
+ setPlaying(false);
+ };
+
+ const handleStart = () => {
+ const parsed = parseArray();
+ if (!parsed) {
+ alert("Invalid array");
+ return;
+ }
+
+ clearTimeout(timerRef.current);
+ setPlaying(false);
+
+ setArr(parsed);
+
+ setTimeout(() => {
+ regenerate();
+ setIdx(0);
+ setPlaying(true);
+ }, 80);
+ };
+ const handlePauseResume = () => {
+ if (steps.length === 0) return;
+ clearTimeout(timerRef.current);
+ setPlaying((p) => !p);
+ };
+ const handleReset = () => {
+ clearTimeout(timerRef.current);
+ setPlaying(false);
+ setIdx(0);
+ };
+ useEffect(() => {
+ clearTimeout(timerRef.current);
+
+ if (playing && idx < steps.length - 1) {
+ timerRef.current = setTimeout(() => setIdx((i) => i + 1), speed);
+ }
+
+ return () => clearTimeout(timerRef.current);
+ }, [playing, idx, steps, speed]);
+
+ const step = steps[idx] || {};
+
+ const getCellColor = (i, s) => {
+ if (!step.dp) return "bg-gray-700";
+
+ if (step.type === "process_cell" && step.i === i && step.sum === s)
+ return "bg-blue-400 text-black";
+
+ if (step.type === "true_set" && step.i === i && step.sum === s)
+ return step.by === "include"
+ ? "bg-green-500 text-black"
+ : "bg-green-100 text-black";
+
+ return step.dp[i][s] ? "bg-green-700" : "bg-gray-800";
+ };
+
+ return (
+
+
+
+ Subset Sum Visualizer
+
+ {/*Controls*/}
+
+
+
+
+ setInputArray(e.target.value)}
+ className="w-full mt-1 p-2 rounded bg-gray-700 border border-gray-600"
+ placeholder="comma-separated"
+ />
+
+
+
+ setTarget(Number(e.target.value))}
+ className="w-20 mt-1 p-2 rounded bg-gray-700 border border-gray-600"
+ />
+
+
+
+
+ setSpeed(Number(e.target.value))}
+ className="w-24 mt-1 p-2 rounded bg-gray-700 border border-gray-600"
+ />
+
+
+
+
+
+
+
+
+
+
+
+ {/* array */}
+
+
+ Array Elements : (Each Row in DP corresponds to one element)
+
+
+
+ {arr.map((v, i) => (
+
+ {v}
+
+ ))}
+
+
+
+ {/*dp table*/}
+
+
+ DP Table (dp[i][sum])
+
+
+ {step.dp && (
+
+
+
+
+ | i / sum |
+ {step.dp[0].map((_, s) => (
+
+ {s}
+ |
+ ))}
+
+
+
+
+ {step.dp.map((row, i) => (
+
+ | i={i} |
+ {row.map((_, s) => (
+
+ {step.dp[i][s] ? "T" : "F"}
+ |
+ ))}
+
+ ))}
+
+
+
+ )}
+
+
+
Explanation
+
+ {step.message || "Press Start to begin."}
+
+
+
+
+
+
Solutions
+
+ {solutions.length > 0 ? (
+
+ {solutions.map((s, i) => (
+
+ # Subset: [{s.join(", ")}]
+
+ ))}
+
+ ) : (
+
No solutions found yet.
+ )}
+
+
Color
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/pages/Recursion/RecursionPage.jsx b/src/pages/Recursion/RecursionPage.jsx
index 525f72f..e48c385 100644
--- a/src/pages/Recursion/RecursionPage.jsx
+++ b/src/pages/Recursion/RecursionPage.jsx
@@ -4,6 +4,7 @@ import MazeSolver from "./MazeSolver";
import NQueens from "./NQueens";
import Sudoku from "./sudokuSolver";
import TowerOfHanoi from "./towerOfHanoi";
+import SubsetSum from "./SubsetSum";
export default function RecursionPage() {
const [selectedAlgo, setSelectedAlgo] = useState("");
const [sidebarOpen, setSidebarOpen] = useState(true);
@@ -34,6 +35,12 @@ export default function RecursionPage() {
);
+ case "SubsetSum":
+ return (
+
+
+
+ );
default:
return (
@@ -79,6 +86,7 @@ export default function RecursionPage() {
+
;
+}
\ No newline at end of file