// Define code content with syntax highlighting const codeContent = [ '0. bool containsNearbyDuplicate(std::vector<int>& nums, int k) {', '1. int size = nums.size();', '2. // create the map, map key is the value of the vector element, map value is the index', '3. std::map<int,int> map1;', '4. for(int i=0; i<size; i++) {', '5. // if already exists', '6. if(map1.find(nums[i]) != map1.end()) {', '7. if(i - map1[nums[i]] <= k) {', '8. return true;', '9. }', '10. }', '11. map1[nums[i]] = i;', '12. }', '13. return false;', '14. }' ]; // Test cases const testCases = [ { array: [1, 2, 3, 1], k: 3, description: "Array [1, 2, 3, 1] with k=3: Expected true (nums[0] == nums[3], |0-3| <= 3)" }, { array: [1, 0, 1, 1], k: 1, description: "Array [1, 0, 1, 1] with k=1: Expected true (nums[2] == nums[3], |2-3| <= 1)" }, { array: [1, 2, 3, 4, 5], k: 2, description: "Array [1, 2, 3, 4, 5] with k=2: Expected false (no duplicates within distance k)" }, { array: [1, 2, 3, 4, 1], k: 4, description: "Array [1, 2, 3, 4, 1] with k=4: Expected true (nums[0] == nums[4], |0-4| == 4 <= 4)" }, { array: [99, 99], k: 1, description: "Array [99, 99] with k=1: Expected true (nums[0] == nums[1], |0-1| <= 1)" }, { array: [1, 2, 3, 4, 5, 6], k: 2, description: "Array [1, 2, 3, 4, 5, 6] with k=2: Expected false (no duplicates)" } ]; // Global variables to track animation state let currentTestCase = 0; let currentStep = 0; let map = new Map(); let result = false; let animationFinished = false; let currentLineHighlighted = -1; // Initialize code display function initCodeDisplay() { const codeDisplay = document.getElementById('codeDisplay'); codeContent.forEach((line, index) => { const lineDiv = document.createElement('div'); lineDiv.className = 'code-line'; lineDiv.setAttribute('data-line', index); lineDiv.innerHTML = line; codeDisplay.appendChild(lineDiv); }); } // Highlight specific line of code function highlightLine(lineNum) { // Remove current highlight if (currentLineHighlighted >= 0) { const currentLine = document.querySelector(`.code-line[data-line="${currentLineHighlighted}"]`); if (currentLine) { currentLine.classList.remove('highlighted'); } } // Add new highlight currentLineHighlighted = lineNum; if (lineNum >= 0) { const targetLine = document.querySelector(`.code-line[data-line="${lineNum}"]`); if (targetLine) { targetLine.classList.add('highlighted'); targetLine.scrollIntoView({ behavior: 'smooth', block: 'center' }); } } } // Update test case description function updateCaseDescription() { const descEl = document.getElementById('caseDescription'); descEl.textContent = testCases[currentTestCase].description; } // Create array visualization function createArrayVisualization() { const container = document.getElementById('arrayContainer'); container.innerHTML = ''; // Clear container const array = testCases[currentTestCase].array; array.forEach((value, index) => { const item = document.createElement('div'); item.className = 'array-item'; item.setAttribute('data-index', index); item.textContent = value; container.appendChild(item); }); } // Update map visualization function updateMapVisualization() { const container = document.getElementById('mapContainer'); container.innerHTML = ''; // Clear container // Display current map entries map.forEach((value, key) => { const item = document.createElement('div'); item.className = 'map-item'; const keyDiv = document.createElement('div'); keyDiv.className = 'map-key'; keyDiv.textContent = `Key: ${key}`; const valueDiv = document.createElement('div'); valueDiv.className = 'map-value'; valueDiv.textContent = `Index: ${value}`; item.appendChild(keyDiv); item.appendChild(valueDiv); container.appendChild(item); }); } // Update explanation text function updateExplanation(text) { document.getElementById('explanation').textContent = text; } // Update result display function updateResult(res, final = false) { const resultEl = document.getElementById('result'); resultEl.textContent = res ? "true" : "false"; if (final) { resultEl.className = res ? "success" : "failure"; } else { resultEl.className = ""; } } // Highlight array item function highlightArrayItem(index, className) { const items = document.querySelectorAll('.array-item'); if (index >= 0 && index < items.length) { // Remove previous highlighting of the same class items.forEach(item => { if (item.classList.contains(className)) { item.classList.remove(className); } }); // Add new highlight items[index].classList.add(className); } } // Remove all highlights from array items function clearArrayHighlights() { const items = document.querySelectorAll('.array-item'); items.forEach(item => { item.classList.remove('current', 'found', 'duplicate'); }); } // Reset animation state function resetAnimation() { currentStep = 0; map = new Map(); result = false; animationFinished = false; highlightLine(-1); clearArrayHighlights(); updateMapVisualization(); updateResult(false); updateExplanation("Animation reset. Click 'Next Step' to begin."); document.getElementById('nextStep').disabled = false; } // Handle test case button clicks function initTestCaseButtons() { const buttons = document.querySelectorAll('.test-btn'); buttons.forEach(button => { button.addEventListener('click', function() { // Update active button buttons.forEach(btn => btn.classList.remove('active')); this.classList.add('active'); // Set current test case currentTestCase = parseInt(this.getAttribute('data-testcase')); // Reset and initialize visualization resetAnimation(); updateCaseDescription(); createArrayVisualization(); }); }); } // Animation steps for containsNearbyDuplicate algorithm async function runAnimationStep() { const array = testCases[currentTestCase].array; const k = testCases[currentTestCase].k; if (animationFinished) { updateExplanation("Animation complete. Choose another test case or click 'Reset' to run again."); return; } switch (currentStep) { case 0: // Function definition highlightLine(0); updateExplanation(`Starting containsNearbyDuplicate function with array [${array.join(', ')}] and k=${k}`); break; case 1: // Get array size highlightLine(1); updateExplanation(`Getting array size: size = ${array.length}`); break; case 2: // Create map highlightLine(3); updateExplanation("Creating an empty map to store values and their indices"); break; default: // Handle main loop iterations const loopIndex = Math.floor((currentStep - 3) / 3); const stepInLoop = (currentStep - 3) % 3; if (loopIndex >= array.length) { // Loop finished, return result highlightLine(13); updateExplanation("No duplicates found within distance k. Returning false."); updateResult(false, true); animationFinished = true; break; } const currentValue = array[loopIndex]; if (stepInLoop === 0) { // Start of loop iteration highlightLine(4); updateExplanation(`Starting iteration ${loopIndex}: Processing element nums[${loopIndex}] = ${currentValue}`); clearArrayHighlights(); highlightArrayItem(loopIndex, 'current'); } else if (stepInLoop === 1) { // Check if value exists in map highlightLine(6); const exists = map.has(currentValue); updateExplanation(`Checking if ${currentValue} already exists in the map: ${exists ? 'Found' : 'Not found'}`); if (exists) { const prevIndex = map.get(currentValue); highlightArrayItem(prevIndex, 'found'); // Check if within k distance highlightLine(7); const diff = loopIndex - prevIndex; const withinK = diff <= k; if (withinK) { // Found duplicate within k distance highlightLine(8); updateExplanation(`Found duplicate! nums[${prevIndex}] = nums[${loopIndex}] = ${currentValue}, and |${loopIndex} - ${prevIndex}| = ${diff} <= ${k}. Returning true.`); updateResult(true, true); highlightArrayItem(loopIndex, 'duplicate'); animationFinished = true; break; } else { updateExplanation(`nums[${prevIndex}] = nums[${loopIndex}] = ${currentValue}, but |${loopIndex} - ${prevIndex}| = ${diff} > ${k}. Continue checking.`); } } } else if (stepInLoop === 2) { // Update map highlightLine(11); map.set(currentValue, loopIndex); updateMapVisualization(); updateExplanation(`Updating map: map[${currentValue}] = ${loopIndex}`); } } currentStep++; } // Initialize on page load window.onload = function() { initCodeDisplay(); initTestCaseButtons(); updateCaseDescription(); createArrayVisualization(); // Set up event listeners document.getElementById('nextStep').addEventListener('click', runAnimationStep); document.getElementById('resetBtn').addEventListener('click', function() { resetAnimation(); createArrayVisualization(); }); };