Files
codetutor/frontend/src/content/algorithms/binary-search.ts

774 lines
26 KiB
TypeScript

import type { AlgorithmDefinition } from '@/lib/visualizations/types';
export const binarySearchAlgorithm: AlgorithmDefinition = {
id: 'binary-search',
title: 'Binary Search',
slug: 'binary-search',
pattern: {
name: 'Binary Search',
description:
'Repeatedly divide the search space in half by comparing to the middle element.',
},
problemStatement:
'Given a sorted array of integers, find the index of a target value. Return -1 if not found.',
intuition:
'In a sorted array, we can eliminate half of the remaining elements with each comparison. Compare the target to the middle element: if smaller, search left half; if larger, search right half.',
code: {
language: 'python',
code: `def binary_search(nums: list[int], target: int) -> int:
left = 0
right = len(nums) - 1
while left <= right:
mid = (left + right) // 2
if nums[mid] == target:
return mid
elif nums[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1`,
},
initialExample: {
input: { nums: [1, 3, 5, 7, 9, 11, 13], target: 9 },
expected: 4,
},
steps: [
// Phase 1: Problem (2 steps)
{
id: 'problem-1',
phase: 'problem',
explanation:
'We have a sorted array [1, 3, 5, 7, 9, 11, 13] and need to find the index of target value 9.',
dataState: {
arrays: [
{
id: 'nums',
elements: [
{ value: 1, index: 0, state: 'normal' },
{ value: 3, index: 1, state: 'normal' },
{ value: 5, index: 2, state: 'normal' },
{ value: 7, index: 3, state: 'normal' },
{ value: 9, index: 4, state: 'normal' },
{ value: 11, index: 5, state: 'normal' },
{ value: 13, index: 6, state: 'normal' },
],
},
],
pointers: [],
variables: [{ id: 'target', name: 'target', value: 9 }],
calculations: [],
},
},
{
id: 'problem-2',
phase: 'problem',
explanation:
'A linear search would check each element, giving O(n) time. Can we use the sorted property to do better?',
dataState: {
arrays: [
{
id: 'nums',
elements: [
{ value: 1, index: 0, state: 'comparing' },
{ value: 3, index: 1, state: 'normal' },
{ value: 5, index: 2, state: 'normal' },
{ value: 7, index: 3, state: 'normal' },
{ value: 9, index: 4, state: 'normal' },
{ value: 11, index: 5, state: 'normal' },
{ value: 13, index: 6, state: 'normal' },
],
},
],
pointers: [],
variables: [{ id: 'target', name: 'target', value: 9 }],
calculations: [],
},
},
// Phase 2: Intuition (3 steps)
{
id: 'intuition-1',
phase: 'intuition',
explanation:
'Key insight: If we check the middle element, we can eliminate half the array with one comparison.',
dataState: {
arrays: [
{
id: 'nums',
elements: [
{ value: 1, index: 0, state: 'normal' },
{ value: 3, index: 1, state: 'normal' },
{ value: 5, index: 2, state: 'normal' },
{ value: 7, index: 3, state: 'highlighted' },
{ value: 9, index: 4, state: 'normal' },
{ value: 11, index: 5, state: 'normal' },
{ value: 13, index: 6, state: 'normal' },
],
},
],
pointers: [
{ id: 'mid', name: 'mid', index: 3, color: 'mid' },
],
variables: [{ id: 'target', name: 'target', value: 9 }],
calculations: [],
},
},
{
id: 'intuition-2',
phase: 'intuition',
explanation:
'Middle element is 7. Since 9 > 7, the target must be in the right half. We can ignore the left half entirely!',
dataState: {
arrays: [
{
id: 'nums',
elements: [
{ value: 1, index: 0, state: 'dimmed' },
{ value: 3, index: 1, state: 'dimmed' },
{ value: 5, index: 2, state: 'dimmed' },
{ value: 7, index: 3, state: 'dimmed' },
{ value: 9, index: 4, state: 'normal' },
{ value: 11, index: 5, state: 'normal' },
{ value: 13, index: 6, state: 'normal' },
],
},
],
pointers: [],
variables: [{ id: 'target', name: 'target', value: 9 }],
calculations: [],
},
},
{
id: 'intuition-3',
phase: 'intuition',
explanation:
'Repeat this process on the remaining half. Each step halves the search space, giving O(log n) time complexity.',
dataState: {
arrays: [
{
id: 'nums',
elements: [
{ value: 1, index: 0, state: 'dimmed' },
{ value: 3, index: 1, state: 'dimmed' },
{ value: 5, index: 2, state: 'dimmed' },
{ value: 7, index: 3, state: 'dimmed' },
{ value: 9, index: 4, state: 'normal' },
{ value: 11, index: 5, state: 'highlighted' },
{ value: 13, index: 6, state: 'normal' },
],
},
],
pointers: [
{ id: 'mid', name: 'mid', index: 5, color: 'mid' },
],
variables: [{ id: 'target', name: 'target', value: 9 }],
calculations: [],
},
},
// Phase 3: Code walkthrough (5 steps)
{
id: 'code-1',
phase: 'code',
explanation:
'Initialize two pointers: left at 0, right at the last index.',
codeLine: 2,
codeHighlightLines: [2, 3],
dataState: {
arrays: [
{
id: 'nums',
elements: [
{ value: 1, index: 0, state: 'normal' },
{ value: 3, index: 1, state: 'normal' },
{ value: 5, index: 2, state: 'normal' },
{ value: 7, index: 3, state: 'normal' },
{ value: 9, index: 4, state: 'normal' },
{ value: 11, index: 5, state: 'normal' },
{ value: 13, index: 6, state: 'normal' },
],
},
],
pointers: [],
variables: [{ id: 'target', name: 'target', value: 9 }],
calculations: [],
},
},
{
id: 'code-2',
phase: 'code',
explanation:
'Loop while the search space is valid (left <= right).',
codeLine: 5,
dataState: {
arrays: [
{
id: 'nums',
elements: [
{ value: 1, index: 0, state: 'normal' },
{ value: 3, index: 1, state: 'normal' },
{ value: 5, index: 2, state: 'normal' },
{ value: 7, index: 3, state: 'normal' },
{ value: 9, index: 4, state: 'normal' },
{ value: 11, index: 5, state: 'normal' },
{ value: 13, index: 6, state: 'normal' },
],
},
],
pointers: [],
variables: [{ id: 'target', name: 'target', value: 9 }],
calculations: [],
},
},
{
id: 'code-3',
phase: 'code',
explanation:
'Calculate the middle index: mid = (left + right) // 2.',
codeLine: 6,
dataState: {
arrays: [
{
id: 'nums',
elements: [
{ value: 1, index: 0, state: 'normal' },
{ value: 3, index: 1, state: 'normal' },
{ value: 5, index: 2, state: 'normal' },
{ value: 7, index: 3, state: 'normal' },
{ value: 9, index: 4, state: 'normal' },
{ value: 11, index: 5, state: 'normal' },
{ value: 13, index: 6, state: 'normal' },
],
},
],
pointers: [],
variables: [{ id: 'target', name: 'target', value: 9 }],
calculations: [],
},
},
{
id: 'code-4',
phase: 'code',
explanation:
'If nums[mid] equals target, we found it! Otherwise, narrow the search space.',
codeLine: 8,
codeHighlightLines: [8, 9, 10, 11, 12, 13],
dataState: {
arrays: [
{
id: 'nums',
elements: [
{ value: 1, index: 0, state: 'normal' },
{ value: 3, index: 1, state: 'normal' },
{ value: 5, index: 2, state: 'normal' },
{ value: 7, index: 3, state: 'normal' },
{ value: 9, index: 4, state: 'normal' },
{ value: 11, index: 5, state: 'normal' },
{ value: 13, index: 6, state: 'normal' },
],
},
],
pointers: [],
variables: [{ id: 'target', name: 'target', value: 9 }],
calculations: [],
},
},
{
id: 'code-5',
phase: 'code',
explanation:
'If target not found after search space is exhausted, return -1.',
codeLine: 15,
dataState: {
arrays: [
{
id: 'nums',
elements: [
{ value: 1, index: 0, state: 'normal' },
{ value: 3, index: 1, state: 'normal' },
{ value: 5, index: 2, state: 'normal' },
{ value: 7, index: 3, state: 'normal' },
{ value: 9, index: 4, state: 'normal' },
{ value: 11, index: 5, state: 'normal' },
{ value: 13, index: 6, state: 'normal' },
],
},
],
pointers: [],
variables: [{ id: 'target', name: 'target', value: 9 }],
calculations: [],
},
},
// Phase 4: Execution (~15 steps)
{
id: 'exec-1',
phase: 'execution',
explanation: 'Initialize left = 0, right = 6 (len(nums) - 1).',
codeLine: 2,
dataState: {
arrays: [
{
id: 'nums',
elements: [
{ value: 1, index: 0, state: 'highlighted' },
{ value: 3, index: 1, state: 'normal' },
{ value: 5, index: 2, state: 'normal' },
{ value: 7, index: 3, state: 'normal' },
{ value: 9, index: 4, state: 'normal' },
{ value: 11, index: 5, state: 'normal' },
{ value: 13, index: 6, state: 'highlighted' },
],
},
],
pointers: [
{ id: 'left', name: 'left', index: 0, color: 'left', showValue: true },
{ id: 'right', name: 'right', index: 6, color: 'right', showValue: true },
],
variables: [
{ id: 'target', name: 'target', value: 9 },
{ id: 'left', name: 'left', value: 0 },
{ id: 'right', name: 'right', value: 6 },
],
calculations: [],
},
},
{
id: 'exec-2',
phase: 'execution',
explanation: 'Check loop condition: left (0) <= right (6)? Yes, enter loop.',
codeLine: 5,
decision: {
question: 'Is left <= right?',
answer: '0 <= 6 = true',
action: 'Enter the while loop',
},
dataState: {
arrays: [
{
id: 'nums',
elements: [
{ value: 1, index: 0, state: 'highlighted' },
{ value: 3, index: 1, state: 'normal' },
{ value: 5, index: 2, state: 'normal' },
{ value: 7, index: 3, state: 'normal' },
{ value: 9, index: 4, state: 'normal' },
{ value: 11, index: 5, state: 'normal' },
{ value: 13, index: 6, state: 'highlighted' },
],
},
],
pointers: [
{ id: 'left', name: 'left', index: 0, color: 'left', showValue: true },
{ id: 'right', name: 'right', index: 6, color: 'right', showValue: true },
],
variables: [
{ id: 'target', name: 'target', value: 9 },
{ id: 'left', name: 'left', value: 0 },
{ id: 'right', name: 'right', value: 6 },
],
calculations: [],
},
},
{
id: 'exec-3',
phase: 'execution',
explanation: 'Calculate mid = (0 + 6) // 2 = 3. Middle element is 7.',
codeLine: 6,
dataState: {
arrays: [
{
id: 'nums',
elements: [
{ value: 1, index: 0, state: 'highlighted' },
{ value: 3, index: 1, state: 'normal' },
{ value: 5, index: 2, state: 'normal' },
{ value: 7, index: 3, state: 'comparing' },
{ value: 9, index: 4, state: 'normal' },
{ value: 11, index: 5, state: 'normal' },
{ value: 13, index: 6, state: 'highlighted' },
],
},
],
pointers: [
{ id: 'left', name: 'left', index: 0, color: 'left', showValue: true },
{ id: 'mid', name: 'mid', index: 3, color: 'mid', showValue: true },
{ id: 'right', name: 'right', index: 6, color: 'right', showValue: true },
],
variables: [
{ id: 'target', name: 'target', value: 9 },
{ id: 'left', name: 'left', value: 0 },
{ id: 'right', name: 'right', value: 6 },
{ id: 'mid', name: 'mid', value: 3, derivation: '(0 + 6) // 2' },
],
calculations: [
{ id: 'calc-1', expression: '(0 + 6) // 2', result: '3', position: 'above' },
],
},
},
{
id: 'exec-4',
phase: 'execution',
explanation: 'Compare: nums[3] = 7 vs target = 9. 7 < 9, so target is in right half.',
codeLine: 10,
decision: {
question: 'Is nums[mid] == target?',
answer: '7 != 9, and 7 < 9',
action: 'Search the right half (left = mid + 1)',
},
dataState: {
arrays: [
{
id: 'nums',
elements: [
{ value: 1, index: 0, state: 'highlighted' },
{ value: 3, index: 1, state: 'normal' },
{ value: 5, index: 2, state: 'normal' },
{ value: 7, index: 3, state: 'comparing' },
{ value: 9, index: 4, state: 'normal' },
{ value: 11, index: 5, state: 'normal' },
{ value: 13, index: 6, state: 'highlighted' },
],
},
],
pointers: [
{ id: 'left', name: 'left', index: 0, color: 'left', showValue: true },
{ id: 'mid', name: 'mid', index: 3, color: 'mid', showValue: true },
{ id: 'right', name: 'right', index: 6, color: 'right', showValue: true },
],
variables: [
{ id: 'target', name: 'target', value: 9 },
{ id: 'left', name: 'left', value: 0 },
{ id: 'right', name: 'right', value: 6 },
{ id: 'mid', name: 'mid', value: 3 },
],
calculations: [
{ id: 'calc-1', expression: '7 < 9', result: 'true', position: 'above' },
],
},
},
{
id: 'exec-5',
phase: 'execution',
explanation: 'Update left = mid + 1 = 4. The left half is eliminated.',
codeLine: 11,
dataState: {
arrays: [
{
id: 'nums',
elements: [
{ value: 1, index: 0, state: 'dimmed' },
{ value: 3, index: 1, state: 'dimmed' },
{ value: 5, index: 2, state: 'dimmed' },
{ value: 7, index: 3, state: 'dimmed' },
{ value: 9, index: 4, state: 'highlighted' },
{ value: 11, index: 5, state: 'normal' },
{ value: 13, index: 6, state: 'highlighted' },
],
},
],
pointers: [
{ id: 'left', name: 'left', index: 4, color: 'left', showValue: true },
{ id: 'right', name: 'right', index: 6, color: 'right', showValue: true },
],
variables: [
{ id: 'target', name: 'target', value: 9 },
{ id: 'left', name: 'left', value: 4, previousValue: 0 },
{ id: 'right', name: 'right', value: 6 },
],
calculations: [],
},
},
{
id: 'exec-6',
phase: 'execution',
explanation: 'Check loop condition: left (4) <= right (6)? Yes, continue.',
codeLine: 5,
decision: {
question: 'Is left <= right?',
answer: '4 <= 6 = true',
action: 'Continue the while loop',
},
dataState: {
arrays: [
{
id: 'nums',
elements: [
{ value: 1, index: 0, state: 'dimmed' },
{ value: 3, index: 1, state: 'dimmed' },
{ value: 5, index: 2, state: 'dimmed' },
{ value: 7, index: 3, state: 'dimmed' },
{ value: 9, index: 4, state: 'highlighted' },
{ value: 11, index: 5, state: 'normal' },
{ value: 13, index: 6, state: 'highlighted' },
],
},
],
pointers: [
{ id: 'left', name: 'left', index: 4, color: 'left', showValue: true },
{ id: 'right', name: 'right', index: 6, color: 'right', showValue: true },
],
variables: [
{ id: 'target', name: 'target', value: 9 },
{ id: 'left', name: 'left', value: 4 },
{ id: 'right', name: 'right', value: 6 },
],
calculations: [],
},
},
{
id: 'exec-7',
phase: 'execution',
explanation: 'Calculate mid = (4 + 6) // 2 = 5. Middle element is 11.',
codeLine: 6,
dataState: {
arrays: [
{
id: 'nums',
elements: [
{ value: 1, index: 0, state: 'dimmed' },
{ value: 3, index: 1, state: 'dimmed' },
{ value: 5, index: 2, state: 'dimmed' },
{ value: 7, index: 3, state: 'dimmed' },
{ value: 9, index: 4, state: 'highlighted' },
{ value: 11, index: 5, state: 'comparing' },
{ value: 13, index: 6, state: 'highlighted' },
],
},
],
pointers: [
{ id: 'left', name: 'left', index: 4, color: 'left', showValue: true },
{ id: 'mid', name: 'mid', index: 5, color: 'mid', showValue: true },
{ id: 'right', name: 'right', index: 6, color: 'right', showValue: true },
],
variables: [
{ id: 'target', name: 'target', value: 9 },
{ id: 'left', name: 'left', value: 4 },
{ id: 'right', name: 'right', value: 6 },
{ id: 'mid', name: 'mid', value: 5, previousValue: 3, derivation: '(4 + 6) // 2' },
],
calculations: [
{ id: 'calc-2', expression: '(4 + 6) // 2', result: '5', position: 'above' },
],
},
},
{
id: 'exec-8',
phase: 'execution',
explanation: 'Compare: nums[5] = 11 vs target = 9. 11 > 9, so target is in left half.',
codeLine: 12,
decision: {
question: 'Is nums[mid] == target?',
answer: '11 != 9, and 11 > 9',
action: 'Search the left half (right = mid - 1)',
},
dataState: {
arrays: [
{
id: 'nums',
elements: [
{ value: 1, index: 0, state: 'dimmed' },
{ value: 3, index: 1, state: 'dimmed' },
{ value: 5, index: 2, state: 'dimmed' },
{ value: 7, index: 3, state: 'dimmed' },
{ value: 9, index: 4, state: 'highlighted' },
{ value: 11, index: 5, state: 'comparing' },
{ value: 13, index: 6, state: 'highlighted' },
],
},
],
pointers: [
{ id: 'left', name: 'left', index: 4, color: 'left', showValue: true },
{ id: 'mid', name: 'mid', index: 5, color: 'mid', showValue: true },
{ id: 'right', name: 'right', index: 6, color: 'right', showValue: true },
],
variables: [
{ id: 'target', name: 'target', value: 9 },
{ id: 'left', name: 'left', value: 4 },
{ id: 'right', name: 'right', value: 6 },
{ id: 'mid', name: 'mid', value: 5 },
],
calculations: [
{ id: 'calc-2', expression: '11 > 9', result: 'true', position: 'above' },
],
},
},
{
id: 'exec-9',
phase: 'execution',
explanation: 'Update right = mid - 1 = 4. The right portion is eliminated.',
codeLine: 13,
dataState: {
arrays: [
{
id: 'nums',
elements: [
{ value: 1, index: 0, state: 'dimmed' },
{ value: 3, index: 1, state: 'dimmed' },
{ value: 5, index: 2, state: 'dimmed' },
{ value: 7, index: 3, state: 'dimmed' },
{ value: 9, index: 4, state: 'highlighted' },
{ value: 11, index: 5, state: 'dimmed' },
{ value: 13, index: 6, state: 'dimmed' },
],
},
],
pointers: [
{ id: 'left', name: 'left', index: 4, color: 'left', showValue: true },
{ id: 'right', name: 'right', index: 4, color: 'right', showValue: true },
],
variables: [
{ id: 'target', name: 'target', value: 9 },
{ id: 'left', name: 'left', value: 4 },
{ id: 'right', name: 'right', value: 4, previousValue: 6 },
],
calculations: [],
},
},
{
id: 'exec-10',
phase: 'execution',
explanation: 'Check loop condition: left (4) <= right (4)? Yes, continue.',
codeLine: 5,
decision: {
question: 'Is left <= right?',
answer: '4 <= 4 = true',
action: 'Continue the while loop',
},
dataState: {
arrays: [
{
id: 'nums',
elements: [
{ value: 1, index: 0, state: 'dimmed' },
{ value: 3, index: 1, state: 'dimmed' },
{ value: 5, index: 2, state: 'dimmed' },
{ value: 7, index: 3, state: 'dimmed' },
{ value: 9, index: 4, state: 'highlighted' },
{ value: 11, index: 5, state: 'dimmed' },
{ value: 13, index: 6, state: 'dimmed' },
],
},
],
pointers: [
{ id: 'left', name: 'left', index: 4, color: 'left', showValue: true },
{ id: 'right', name: 'right', index: 4, color: 'right', showValue: true },
],
variables: [
{ id: 'target', name: 'target', value: 9 },
{ id: 'left', name: 'left', value: 4 },
{ id: 'right', name: 'right', value: 4 },
],
calculations: [],
},
},
{
id: 'exec-11',
phase: 'execution',
explanation: 'Calculate mid = (4 + 4) // 2 = 4. Middle element is 9.',
codeLine: 6,
dataState: {
arrays: [
{
id: 'nums',
elements: [
{ value: 1, index: 0, state: 'dimmed' },
{ value: 3, index: 1, state: 'dimmed' },
{ value: 5, index: 2, state: 'dimmed' },
{ value: 7, index: 3, state: 'dimmed' },
{ value: 9, index: 4, state: 'comparing' },
{ value: 11, index: 5, state: 'dimmed' },
{ value: 13, index: 6, state: 'dimmed' },
],
},
],
pointers: [
{ id: 'left', name: 'left', index: 4, color: 'left', showValue: true },
{ id: 'mid', name: 'mid', index: 4, color: 'mid', showValue: true },
{ id: 'right', name: 'right', index: 4, color: 'right', showValue: true },
],
variables: [
{ id: 'target', name: 'target', value: 9 },
{ id: 'left', name: 'left', value: 4 },
{ id: 'right', name: 'right', value: 4 },
{ id: 'mid', name: 'mid', value: 4, previousValue: 5, derivation: '(4 + 4) // 2' },
],
calculations: [
{ id: 'calc-3', expression: '(4 + 4) // 2', result: '4', position: 'above' },
],
},
},
{
id: 'exec-12',
phase: 'execution',
explanation: 'Compare: nums[4] = 9 vs target = 9. Found it!',
codeLine: 8,
decision: {
question: 'Is nums[mid] == target?',
answer: '9 == 9 = true',
action: 'Return mid = 4',
},
dataState: {
arrays: [
{
id: 'nums',
elements: [
{ value: 1, index: 0, state: 'dimmed' },
{ value: 3, index: 1, state: 'dimmed' },
{ value: 5, index: 2, state: 'dimmed' },
{ value: 7, index: 3, state: 'dimmed' },
{ value: 9, index: 4, state: 'success' },
{ value: 11, index: 5, state: 'dimmed' },
{ value: 13, index: 6, state: 'dimmed' },
],
},
],
pointers: [
{ id: 'mid', name: 'mid', index: 4, color: 'mid', showValue: true },
],
variables: [
{ id: 'target', name: 'target', value: 9 },
{ id: 'mid', name: 'mid', value: 4 },
],
calculations: [
{ id: 'calc-3', expression: '9 == 9', result: 'true', position: 'above' },
],
},
},
{
id: 'exec-13',
phase: 'execution',
explanation:
'Return 4. Found target 9 at index 4 in just 3 comparisons! O(log n) time complexity.',
codeLine: 9,
dataState: {
arrays: [
{
id: 'nums',
elements: [
{ value: 1, index: 0, state: 'dimmed' },
{ value: 3, index: 1, state: 'dimmed' },
{ value: 5, index: 2, state: 'dimmed' },
{ value: 7, index: 3, state: 'dimmed' },
{ value: 9, index: 4, state: 'success' },
{ value: 11, index: 5, state: 'dimmed' },
{ value: 13, index: 6, state: 'dimmed' },
],
},
],
pointers: [
{ id: 'mid', name: 'mid', index: 4, color: 'mid', showValue: true },
],
variables: [
{ id: 'target', name: 'target', value: 9 },
{ id: 'result', name: 'result', value: 4 },
],
calculations: [],
},
},
],
};