CoolFace
Apppublic

sanket3280/code-execution

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
complexityAnalyzer.js326 linesDownload Raw Back to utils
1/**2 * Complexity Analyzer - Estimates time and space complexity from execution data3 * Based on HackerEarth-style analysis with multiple input sizes4 */5 6/**7 * Estimate time complexity based on execution time ratios8 * @param {Array<{inputSize: number, timeMs: number}>} timeData - Array of execution times with input sizes9 * @returns {string} Estimated time complexity (e.g., "O(n)", "O(n²)", "O(n log n)")10 */11function estimateTimeComplexity(timeData) {12  if (!timeData || timeData.length < 2) {13    // If we have data but not enough to compare, analyze the single point14    if (timeData && timeData.length === 1) {15      return timeData[0].timeMs < 1 ? "O(1)" : "O(n)";16    }17    return "O(n)"; // Default assumption18  }19 20  // Sort by input size21  const sorted = [...timeData].sort((a, b) => a.inputSize - b.inputSize);22  23  // Calculate growth ratios24  const ratios = [];25  for (let i = 1; i < sorted.length; i++) {26    const sizeRatio = sorted[i].inputSize / Math.max(sorted[i - 1].inputSize, 1);27    const timeRatio = sorted[i].timeMs / Math.max(sorted[i - 1].timeMs, 0.001);28    ratios.push({ sizeRatio, timeRatio });29  }30 31  // Average time ratio32  const avgTimeRatio = ratios.reduce((sum, r) => sum + r.timeRatio, 0) / ratios.length;33  const avgSizeRatio = ratios.reduce((sum, r) => sum + r.sizeRatio, 0) / ratios.length;34 35  // Classify complexity based on growth pattern36  // O(1) - Constant: time doesn't grow with input37  if (avgTimeRatio < 1.2) return "O(1)";38  39  // O(log n) - Logarithmic: time grows slowly40  if (avgTimeRatio < Math.log2(avgSizeRatio) * 1.3) return "O(log n)";41  42  // O(n) - Linear: time grows proportionally43  if (Math.abs(avgTimeRatio - avgSizeRatio) < avgSizeRatio * 0.3) return "O(n)";44  45  // O(n log n) - Linearithmic: time grows slightly faster than linear46  if (avgTimeRatio < avgSizeRatio * Math.log2(avgSizeRatio) * 1.3) return "O(n log n)";47  48  // O(n²) - Quadratic: time grows with square of input49  const expectedQuadratic = Math.pow(avgSizeRatio, 2);50  if (Math.abs(avgTimeRatio - expectedQuadratic) < expectedQuadratic * 0.5) return "O(n²)";51  52  // O(2^n) or worse - Exponential53  if (avgTimeRatio > Math.pow(avgSizeRatio, 2) * 2) return "O(2^n)";54  55  // Default to O(n) if pattern is unclear56  return "O(n)";57}58 59/**60 * Estimate space complexity based on memory usage ratios61 * @param {Array<{inputSize: number, memoryKB: number}>} memoryData - Array of memory usage with input sizes62 * @returns {string} Estimated space complexity63 */64function estimateSpaceComplexity(memoryData) {65  if (!memoryData || memoryData.length < 2) return "O(1)"; // Default assumption66 67  // Sort by input size68  const sorted = [...memoryData].sort((a, b) => a.inputSize - b.inputSize);69  70  // Calculate growth ratios71  const ratios = [];72  for (let i = 1; i < sorted.length; i++) {73    const sizeRatio = sorted[i].inputSize / sorted[i - 1].inputSize;74    const memRatio = sorted[i].memoryKB / Math.max(sorted[i - 1].memoryKB, 1); // Avoid division by zero75    ratios.push({ sizeRatio, memRatio });76  }77 78  // Average memory ratio79  const avgMemRatio = ratios.reduce((sum, r) => sum + r.memRatio, 0) / ratios.length;80  const avgSizeRatio = ratios.reduce((sum, r) => sum + r.sizeRatio, 0) / ratios.length;81 82  // Classify complexity based on growth pattern83  // O(1) - Constant: memory doesn't grow with input84  if (avgMemRatio < 1.2) return "O(1)";85  86  // O(log n) - Logarithmic: memory grows slowly87  if (avgMemRatio < avgSizeRatio * 0.5) return "O(log n)";88  89  // O(n) - Linear: memory grows proportionally90  if (Math.abs(avgMemRatio - avgSizeRatio) < 0.5) return "O(n)";91  92  // O(n²) - Quadratic: memory grows with square of input93  if (avgMemRatio > avgSizeRatio * 2) return "O(n²)";94  95  // Default to O(1) if pattern is unclear (most algorithms use constant extra space)96  return "O(1)";97}98 99/**100 * Estimate input size from test case input101 * @param {string} input - Test case input (JSON format)102 * @returns {number} Estimated input size103 */104function estimateInputSize(input) {105  try {106    const parsed = JSON.parse(input);107    108    // Find the largest array or string in the input109    let maxSize = 1;110    111    const findSize = (obj) => {112      if (Array.isArray(obj)) {113        maxSize = Math.max(maxSize, obj.length);114        obj.forEach(findSize);115      } else if (typeof obj === 'string') {116        maxSize = Math.max(maxSize, obj.length);117      } else if (typeof obj === 'object' && obj !== null) {118        Object.values(obj).forEach(findSize);119      }120    };121    122    findSize(parsed);123    return maxSize;124  } catch (e) {125    // If parsing fails, estimate from string length126    return Math.max(1, Math.floor(input.length / 10));127  }128}129 130/**131 * Analyze source code for complexity patterns132 * @param {string} sourceCode - The source code to analyze133 * @returns {Object} Detected complexity patterns134 */135function analyzeSourceCode(sourceCode) {136  if (!sourceCode) return { timeComplexity: null, spaceComplexity: null };137  138  const code = sourceCode.toLowerCase();139  140  // Time Complexity Detection141  let timeComplexity = null;142  143  // O(2^n) - Exponential: recursive calls without memoization144  if ((code.match(/function.*\(.*\).*{[\s\S]*?\1\(/g) || []).length > 1 && 145      !code.includes('memo') && !code.includes('dp') && !code.includes('cache')) {146    timeComplexity = "O(2^n)";147  }148  // O(n³) - Cubic: three nested loops149  else if ((code.match(/for\s*\(|while\s*\(/g) || []).length >= 3) {150    const nestedLoops = (code.match(/for[\s\S]{0,200}for[\s\S]{0,200}for/g) || []).length;151    if (nestedLoops > 0) timeComplexity = "O(n³)";152  }153  // O(n²) - Quadratic: two nested loops154  if (!timeComplexity && (code.match(/for\s*\(|while\s*\(/g) || []).length >= 2) {155    const nestedLoops = (code.match(/for[\s\S]{0,200}for/g) || []).length;156    if (nestedLoops > 0) timeComplexity = "O(n²)";157  }158  // O(n log n) - Linearithmic: sorting or divide-and-conquer159  if (!timeComplexity && (code.includes('sort') || code.includes('mergesort') || code.includes('quicksort'))) {160    timeComplexity = "O(n log n)";161  }162  // O(n) - Linear: single loop163  if (!timeComplexity && (code.match(/for\s*\(|while\s*\(/g) || []).length >= 1) {164    timeComplexity = "O(n)";165  }166  // O(log n) - Logarithmic: binary search pattern167  if (!timeComplexity && (code.includes('binary') || (code.includes('while') && code.includes('/= 2')))) {168    timeComplexity = "O(log n)";169  }170  // O(1) - Constant: no loops171  if (!timeComplexity) {172    timeComplexity = "O(1)";173  }174  175  // Space Complexity Detection176  let spaceComplexity = null;177  178  // O(n²) - Quadratic space: 2D arrays179  if (code.match(/\[\s*\[/g) || 180      (code.includes('array') && code.match(/array.*array/gi))) {181    spaceComplexity = "O(n²)";182  }183  // O(n) - Linear space: arrays, lists, hash maps, objects184  else if (code.match(/=\s*\[\]/) ||  // const arr = []185           code.match(/=\s*\{\}/) ||  // const map = {}186           code.match(/=\s*new\s+(array|map|set)/i) ||  // new Map(), new Set()187           code.includes('array') || 188           code.includes('list') || 189           code.includes('dict') || 190           code.includes('hashmap') ||191           code.match(/const\s+\w+\s*=\s*\{\}/)) {  // const obj = {}192    spaceComplexity = "O(n)";193  }194  // O(log n) - Logarithmic space: recursion depth195  else if (code.includes('return') && code.match(/function.*\(.*\).*{[\s\S]*?\1\(/g)) {196    spaceComplexity = "O(log n)";197  }198  // O(1) - Constant space: only variables199  else {200    spaceComplexity = "O(1)";201  }202  203  console.log('🔍 Source Code Analysis:');204  console.log('   Time Complexity:', timeComplexity);205  console.log('   Space Complexity:', spaceComplexity);206  console.log('   Code snippet:', code.substring(0, 200));207  208  return { timeComplexity, spaceComplexity };209}210 211/**212 * Analyze complexity from test case results213 * @param {Array} testCaseResults - Array of test case results with executionTime and memoryUsed214 * @param {string} sourceCode - Optional source code for static analysis215 * @returns {Object} Complexity analysis with time and space complexity216 */217function analyzeComplexity(testCaseResults, sourceCode = null) {218  if (!testCaseResults || testCaseResults.length === 0) {219    return {220      timeComplexity: "O(n)",221      spaceComplexity: "O(1)",222      avgTimeMs: 0,223      maxTimeMs: 0,224      avgMemoryKB: 0,225      maxMemoryKB: 0,226      performanceLog: generatePerformanceLog("O(n)", "O(1)", 0, 0)227    };228  }229 230  // Extract time and memory data with input sizes231  const timeData = [];232  const memoryData = [];233  234  testCaseResults.forEach(result => {235    if (result.executionTime !== null && result.executionTime !== undefined && result.executionTime > 0) {236      const inputSize = estimateInputSize(result.input || "{}");237      timeData.push({238        inputSize,239        timeMs: result.executionTime * 1000 // Convert seconds to ms240      });241    }242    243    if (result.memoryUsed !== null && result.memoryUsed !== undefined && result.memoryUsed > 0) {244      const inputSize = estimateInputSize(result.input || "{}");245      memoryData.push({246        inputSize,247        memoryKB: result.memoryUsed248      });249    }250  });251 252  // Calculate statistics253  const times = timeData.map(d => d.timeMs);254  const memories = memoryData.map(d => d.memoryKB);255  256  const avgTimeMs = times.length > 0 ? times.reduce((a, b) => a + b, 0) / times.length : 0;257  const maxTimeMs = times.length > 0 ? Math.max(...times) : 0;258  259  // Estimate complexities from execution data260  const executionTimeComplexity = estimateTimeComplexity(timeData);261  const executionSpaceComplexity = estimateSpaceComplexity(memoryData);262  263  // Analyze source code if provided (do this ONCE)264  const codeAnalysis = sourceCode ? analyzeSourceCode(sourceCode) : { timeComplexity: null, spaceComplexity: null };265  266  // Prefer code analysis over execution analysis (more accurate)267  const timeComplexity = codeAnalysis.timeComplexity || executionTimeComplexity;268  const spaceComplexity = codeAnalysis.spaceComplexity || executionSpaceComplexity;269  270  // Use estimated memory based on space complexity if no actual data271  let avgMemoryKB = memories.length > 0 ? memories.reduce((a, b) => a + b, 0) / memories.length : 0;272  let maxMemoryKB = memories.length > 0 ? Math.max(...memories) : 0;273  274  // If no memory data, estimate based on space complexity275  if (avgMemoryKB === 0) {276    if (spaceComplexity === 'O(n²)') {277      avgMemoryKB = 10240; // ~10MB for quadratic278      maxMemoryKB = 20480;279    } else if (spaceComplexity === 'O(n)') {280      avgMemoryKB = 2048; // ~2MB for linear281      maxMemoryKB = 4096;282    } else {283      avgMemoryKB = 512; // ~512KB for constant284      maxMemoryKB = 1024;285    }286  }287 288  return {289    timeComplexity,290    spaceComplexity,291    avgTimeMs: parseFloat(avgTimeMs.toFixed(2)),292    maxTimeMs: parseFloat(maxTimeMs.toFixed(2)),293    avgMemoryKB: parseFloat(avgMemoryKB.toFixed(2)),294    maxMemoryKB: parseFloat(maxMemoryKB.toFixed(2)),295    performanceLog: generatePerformanceLog(timeComplexity, spaceComplexity, avgTimeMs, avgMemoryKB)296  };297}298 299/**300 * Generate performance log in HackerEarth style301 * @param {string} timeComplexity - Estimated time complexity302 * @param {string} spaceComplexity - Estimated space complexity303 * @param {number} avgTimeMs - Average execution time in milliseconds304 * @param {number} avgMemoryKB - Average memory usage in KB305 * @returns {string} Formatted performance log306 */307function generatePerformanceLog(timeComplexity, spaceComplexity, avgTimeMs, avgMemoryKB) {308  return `------------------------------------------------------------309⚙️  Algorithm Performance Analysis310------------------------------------------------------------311🕒 Estimated Time Complexity  : ${timeComplexity}312💾 Estimated Space Complexity : ${spaceComplexity}313📊 Avg Execution Time         : ${avgTimeMs.toFixed(2)} ms314📈 Avg Memory Usage           : ${(avgMemoryKB / 1024).toFixed(2)} MB315------------------------------------------------------------`;316}317 318module.exports = {319  estimateTimeComplexity,320  estimateSpaceComplexity,321  estimateInputSize,322  analyzeComplexity,323  analyzeSourceCode,324  generatePerformanceLog325};326