diff --git a/README.md b/README.md
index d57c2fa..9748f7b 100644
--- a/README.md
+++ b/README.md
@@ -44,6 +44,31 @@ Understand searching logic through dynamic comparisons.
---
+#### 🔹 Sliding Window Algorithms
+Demonstrate how the sliding window technique optimizes time complexity in problems involving subarrays and substrings.
+
+**Algorithms Included:**
+- Maximum Sum of Subarray of Size K
+
+**Interactive Options:**
+- Adjust window size
+- Control animation speed
+- Real-time window movement visualization
+- Dynamic highlighting of elements within the window
+- Step-by-step explanation of window expansion and contraction
+
+**Algorithm Overview:**
+The Sliding Window technique maintains a subset of elements using two pointers (start, end) that "slide" over the array or string to efficiently compute results without redundant recalculations.
+
+**General Approach:**
+1. Initialize start and end pointers
+2. Expand the window by moving end
+3. Process or evaluate current window state
+4. Shrink the window from start when constraints are violated
+5. Update the result as needed during traversal
+
+---
+
#### 🔹 Pathfinding Algorithms (Graph / 2D Grid)
Visualize how algorithms explore and find paths across a grid.
@@ -186,12 +211,19 @@ Algo-Visualizer/
│ ├── algorithms/
│ │ ├── sorting/
│ │ ├── searching/
+│ │ ├── sliding-window/
│ │ ├── pathfinding/
│ │ ├── graph/
│ ├── components/
+│ │ ├── sorting/
+│ │ ├── searching/
+│ │ ├── sliding-window/
+│ │ ├── pathfinding/
+│ │ ├── graph/
│ ├── pages/
│ │ ├── sorting/
│ │ ├── searching/
+│ │ ├── sliding-window/
│ │ ├── pathfinding/
│ │ ├── graph/
│ ├── utils/
diff --git a/public/Sliding-Window.png b/public/Sliding-Window.png
new file mode 100644
index 0000000..037c7a2
Binary files /dev/null and b/public/Sliding-Window.png differ
diff --git a/src/App.jsx b/src/App.jsx
index 71a3bf5..68f06cb 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -8,6 +8,7 @@ import DSPage from "./pages/dataStructure/datastructurePage.jsx"
import DynamicProgrammingPage from "./pages/dynamic-programming/DyanmicProgrammingPage.jsx";
import Searchingpage from "./pages/searching/searchingPage";
import RecursionPage from "./pages/Recursion/RecursionPage";
+import SlidingWindowPage from "./pages/sliding-window/SlidingWindowPage";
function App() {
return (
@@ -20,6 +21,7 @@ function App() {
} />
} />
}/>
+ }/>
);
diff --git a/src/algorithms/sliding-window/maxSumSubarray.js b/src/algorithms/sliding-window/maxSumSubarray.js
new file mode 100644
index 0000000..4400e5e
--- /dev/null
+++ b/src/algorithms/sliding-window/maxSumSubarray.js
@@ -0,0 +1,88 @@
+export function* maxSumSubarray(array, k) {
+ if (array.length === 0) {
+ yield {
+ type: "error",
+ message: "Array cannot be empty",
+ windowStart: -1, windowEnd: -1, currentSum: 0, maxSum: 0
+ };
+ return;
+ }
+ if (k > array.length) {
+ yield {
+ type: "error",
+ message: `Window size ${k} cannot be greater than array length ${array.length}`,
+ windowStart: -1, windowEnd: -1, currentSum: 0, maxSum: 0
+ };
+ return;
+ }
+ if (k <= 0) {
+ yield {
+ type: "error",
+ message: "Window size must be greater than 0",
+ windowStart: -1, windowEnd: -1, currentSum: 0, maxSum: 0
+ };
+ return;
+ }
+ let windowStart = 0;
+ let windowEnd = 0;
+ let currentSum = 0;
+ let maxSum = Number.NEGATIVE_INFINITY;
+ yield {
+ type: "initialize",
+ message: `Initializing: Calculating sum of first window [0, ${k - 1}]`,
+ windowStart: 0,windowEnd: k - 1,currentSum: 0,maxSum: 0
+ };
+ for (let i = 0; i < k; i++) {
+ currentSum += array[i];
+ yield {
+ type: "expand",
+ message: `Adding element at index ${i}: ${array[i]}. Current sum: ${currentSum}`,
+ windowStart: 0,windowEnd: i,currentSum: currentSum,maxSum: maxSum
+ };
+ }
+ maxSum = currentSum;
+ windowEnd = k - 1;
+
+ yield {
+ type: "window_ready",
+ message: `First window sum: ${currentSum}. This is our initial maximum.`,
+ windowStart: 0, windowEnd: k - 1, currentSum: currentSum, maxSum: maxSum
+ };
+ for (let i = k; i < array.length; i++) {
+ const removedElement = array[i - k];
+ const addedElement = array[i];
+ yield {
+ type: "slide_start",
+ message: `Sliding window: Removing element at index ${i - k} (${removedElement}), adding element at index ${i} (${addedElement})`,
+ windowStart: i - k, windowEnd: i - 1, currentSum: currentSum, maxSum: maxSum, removedIndex: i - k, addedIndex: i
+ };
+ currentSum = currentSum - removedElement + addedElement;
+ windowStart = i - k + 1;
+ windowEnd = i;
+ yield {
+ type: "slide_update",
+ message: `Window moved: New sum = ${currentSum} (previous: ${currentSum + removedElement - addedElement}, removed: ${removedElement}, added: ${addedElement})`,
+ windowStart: windowStart, windowEnd: windowEnd, currentSum: currentSum, maxSum: maxSum, removedIndex: i - k, addedIndex: i
+ };
+ if (currentSum > maxSum) {
+ maxSum = currentSum;
+ yield {
+ type: "new_max",
+ message: `New maximum found! Sum: ${maxSum} at window [${windowStart}, ${windowEnd}]`,
+ windowStart: windowStart, windowEnd: windowEnd, currentSum: currentSum, maxSum: maxSum
+ };
+ } else {
+ yield {
+ type: "window_ready",
+ message: `Current sum: ${currentSum} (not greater than max: ${maxSum})`,
+ windowStart: windowStart, windowEnd: windowEnd, currentSum: currentSum, maxSum: maxSum
+ };
+ }
+ }
+ yield {
+ type: "done",
+ message: `Algorithm completed! Maximum sum of subarray of size ${k} is ${maxSum}`,
+ windowStart: windowStart, windowEnd: windowEnd, currentSum: currentSum, maxSum: maxSum
+ };
+}
+
diff --git a/src/components/sliding-window/MaxSumSubarrayVisualizer.jsx b/src/components/sliding-window/MaxSumSubarrayVisualizer.jsx
new file mode 100644
index 0000000..f12146d
--- /dev/null
+++ b/src/components/sliding-window/MaxSumSubarrayVisualizer.jsx
@@ -0,0 +1,69 @@
+import React from "react";
+
+export default function MaxSumSubarrayVisualizer({array, windowStart, windowEnd, currentSum, maxSum, type, removedIndex, addedIndex}) {
+ if (!array || array.length === 0) {
+ return (
+
+ No array data to visualize
+
+ );
+ }
+ const maxValue = Math.max(...array, 1);
+ const containerHeight = 320;
+
+ const getColor = (idx) => {
+ if (windowStart < 0 || windowEnd < 0) return "bg-gray-600";
+ if (type === "slide_start" && idx === removedIndex) return "bg-red-500";
+ if ((type === "slide_start" || type === "slide_update") && idx === addedIndex)
+ return "bg-yellow-400";
+ if (type === "new_max" && idx >= windowStart && idx <= windowEnd)
+ return "bg-purple-500 animate-pulse";
+ if (idx === windowStart || idx === windowEnd) return "bg-green-500";
+ if (idx >= windowStart && idx <= windowEnd) return "bg-blue-500";
+ return "bg-gray-500";
+ };
+
+ return (
+
+
+ {array.map((value, idx) => {
+ const color = getColor(idx);
+ const height = Math.max((value / maxValue) * containerHeight, 40);
+ return (
+
+ );
+ })}
+
+ {windowStart >= 0 && windowEnd >= 0 && (
+
+
+ Window: {" "}
+
+ [{windowStart}, {windowEnd}]
+
+
+
+ Sum: {" "}
+
+ {currentSum}
+
+
+
+ Max: {" "}
+
+ {maxSum !== Number.NEGATIVE_INFINITY ? maxSum : "N/A"}
+
+
+
+ )}
+
+ );
+}
diff --git a/src/pages/Homepage.jsx b/src/pages/Homepage.jsx
index c9df667..318180d 100644
--- a/src/pages/Homepage.jsx
+++ b/src/pages/Homepage.jsx
@@ -23,6 +23,15 @@ const sections = [
link: "/searching",
flag: false
},
+ {
+ title: "Sliding Window Algorithms",
+ description:
+ "Visualize how the sliding window technique efficiently processes subarrays and substrings with dynamic window movement.",
+ phase: "Phase 1 (MVP)",
+ img: "/Sliding-Window.png",
+ link: "/sliding-window",
+ flag: false
+ },
{
title: "Pathfinding Algorithms",
description:
diff --git a/src/pages/sliding-window/MaxSumSubarray.jsx b/src/pages/sliding-window/MaxSumSubarray.jsx
new file mode 100644
index 0000000..2b92d82
--- /dev/null
+++ b/src/pages/sliding-window/MaxSumSubarray.jsx
@@ -0,0 +1,218 @@
+import React, { useState, useEffect, useRef } from "react";
+import { Toaster, toast } from "react-hot-toast";
+import MaxSumSubarrayVisualizer from "../../components/sliding-window/MaxSumSubarrayVisualizer";
+import { maxSumSubarray } from "../../algorithms/sliding-window/maxSumSubarray";
+
+export default function MaxSumSubarray() {
+ const [array, setArray] = useState([2, 1, 5, 1, 3, 2]);
+ const [input, setInput] = useState("2,1,5,1,3,2");
+ const [windowSize, setWindowSize] = useState(3);
+ const [speed, setSpeed] = useState(800);
+ const [isRunning, setIsRunning] = useState(false);
+ const [currentStep, setCurrentStep] = useState(null);
+ const [steps, setSteps] = useState([]);
+ const [currentStepIndex, setCurrentStepIndex] = useState(0);
+ const intervalRef = useRef(null);
+ const hasNotifiedRef = useRef(false);
+
+ // Handle input
+ const handleInputChange = (e) => {
+ const value = e.target.value;
+ setInput(value);
+ const numbers = value
+ .split(",")
+ .map((n) => parseInt(n.trim()))
+ .filter((n) => !isNaN(n));
+ setArray(numbers);
+ resetSteps();
+ };
+ const handleWindowSizeChange = (e) => {
+ const size = parseInt(e.target.value);
+ if (!isNaN(size) && size > 0) {
+ setWindowSize(size);
+ resetSteps();
+ }
+ };
+ const resetSteps = () => {
+ setCurrentStep(null);
+ setSteps([]);
+ setCurrentStepIndex(0);
+ hasNotifiedRef.current = false;
+ };
+ const startVisualization = async () => {
+ if (isRunning || array.length === 0) {
+ toast.error("Please ensure the array is valid.");
+ return;
+ }
+ if (windowSize > array.length) {
+ toast.error(`Window size cannot exceed array length (${array.length})`);
+ return;
+ }
+ if (windowSize <= 0) {
+ toast.error("Window size must be greater than 0");
+ return;
+ }
+ setIsRunning(true);
+ resetSteps();
+
+ const gen = maxSumSubarray(array, windowSize);
+ const allSteps = [];
+ try {
+ for (let step of gen) allSteps.push(step);
+ setSteps(allSteps);
+ setCurrentStep(allSteps[0]);
+ }catch (error) {
+ toast.error(error.message);
+ setIsRunning(false);
+ }
+ };
+ useEffect(() => {
+ if (!isRunning || steps.length === 0) return;
+
+ clearInterval(intervalRef.current);
+ let index = 0;
+ intervalRef.current = setInterval(() => {
+ setCurrentStepIndex((prev) => {
+ index = prev + 1;
+
+ if (index >= steps.length) {
+ clearInterval(intervalRef.current);
+ setIsRunning(false);
+
+ if (!hasNotifiedRef.current && steps.length > 0) {
+ const finalStep = steps[steps.length - 1];
+ toast.success(
+ `✅ Maximum sum found: ${finalStep.maxSum} (Window: [${finalStep.windowStart}, ${finalStep.windowEnd}])`,
+ { duration: 3000 }
+ );
+ hasNotifiedRef.current = true;
+ }
+ return prev;
+ }
+ const step = steps[index];
+ setCurrentStep(step);
+ if (step.type === "new_max") {
+ toast.success(` Yo! New maximum found: ${step.maxSum}`, {
+ duration: 2000,
+ });
+ }
+ return index;
+ });
+ }, speed);
+ return () => clearInterval(intervalRef.current);
+ }, [isRunning, steps, speed]);
+
+ const handleReset = () => {
+ setIsRunning(false);
+ clearInterval(intervalRef.current);
+ setArray([2, 1, 5, 1, 3, 2]);
+ setInput("2,1,5,1,3,2");
+ setWindowSize(3);
+ setSpeed(800);
+ resetSteps();
+ };
+
+ return (
+
+
+
+ Sliding Window — Max Sum Subarray
+
+ {/* Controls */}
+
+
+
+
+
+ Speed ({speed}ms)
+
+ setSpeed(Number(e.target.value))}
+ disabled={isRunning}
+ className="w-40 accent-indigo-500" />
+
+
+
+ {isRunning ? "Running..." : "Start"}
+
+
+ Reset
+
+
+
+
+
+
+ {currentStep && (
+
+
+ Step {currentStepIndex + 1} / {steps.length}
+
+ {currentStep.message && (
+
{currentStep.message}
+ )}
+
+
+ Window: {" "}
+
+ [{currentStep.windowStart}, {currentStep.windowEnd}]
+
+
+
+ Current Sum: {" "}
+
+ {currentStep.currentSum}
+
+
+
+ Max Sum: {" "}
+
+ {currentStep.maxSum}
+
+
+
+
+ )}
+
+ );
+}
+function Control({ label, type = "text", value, onChange, placeholder, disabled }) {
+ return (
+
+ {label}
+
+
+ );
+}
diff --git a/src/pages/sliding-window/SlidingWindowPage.jsx b/src/pages/sliding-window/SlidingWindowPage.jsx
new file mode 100644
index 0000000..60a8ae6
--- /dev/null
+++ b/src/pages/sliding-window/SlidingWindowPage.jsx
@@ -0,0 +1,63 @@
+import React, { useState } from "react";
+import MaxSumSubarray from "./MaxSumSubarray";
+
+export default function SlidingWindowPage() {
+ const [selectedAlgo, setSelectedAlgo] = useState("");
+ const renderAlgorithm = () => {
+ switch (selectedAlgo) {
+ case "maxSumSubarray":
+ return ;
+ default:
+ return (
+
+
+
+
+
+ Sliding Window Visualizer
+
+
+ Understand how the sliding window technique optimizes time complexity
+ in problems involving subarrays and substrings. Watch the window
+ dynamically move and update across the input sequence!
+
+
+
+
+
+ );
+ }
+ };
+
+ return (
+
+ {/* Sidebar */}
+
+
+ Sliding Window Panel
+
+
+
Algorithm:
+
setSelectedAlgo(e.target.value)}
+ className="w-full p-2 rounded bg-[#1e293b] text-white border border-gray-600 focus:ring-2 focus:ring-indigo-500 focus:outline-none cursor-pointer">
+ Select Algorithm
+ Maximum Sum Subarray
+
+
+
setSelectedAlgo("")} className="w-full mt-4 py-2 bg-gray-700 hover:bg-gray-600 rounded transition font-medium cursor-pointer">
+ Reset
+
+
+
+ ← Back to Home
+
+
+
+
+ {renderAlgorithm()}
+
+
+
+ );
+}
+