CoreTechED

Loading

Master Sliding Window interview questions in C: 20 theoretical Q&A plus full code for fixed and variable windows, frequency maps, and edge cases.

Sliding Window Interview Questions in C: 20 Q&A

Sliding Window Technique Interview Questions in C: A Comprehensive Tutorial

The Sliding Window Technique is a top-tier interview topic because it appears in dozens of variations across array, string, and streaming problems. Interviewers test both your conceptual understanding and your ability to implement it correctly in C with safe memory practices.

This tutorial combines 20 curated interview questions with model answers and full C implementations of the most representative problems across easy, medium, and hard levels. Each code block is C99/C11-compliant, includes explicit memory management, and has verified expected output.


Conceptual Introduction & Fundamentals

What is the Sliding Window Technique?

The Sliding Window Technique processes a contiguous range of elements (a “window”) by expanding or shrinking it as it traverses the data, reusing work from the previous window instead of recomputing.

Core properties:

  • Maintains a window using two pointers (usually left and right).
  • Each element enters and leaves the window at most once → O(n) time.
  • Uses O(1) to O(k) auxiliary space depending on the problem.
  • Works on arrays, strings, and streams.

Why Interviewers Love It

  • Discriminating: Separates candidates who can reason about invariants.
  • Practical: Appears in real systems (network buffers, log analysis).
  • Composable: Combines with hashing, deques, and prefix sums.
  • Testable: Easy to design follow-up questions.

The Two Variants

VariantWindow SizeTypical Problems
Fixed-SizeConstant k givenMax sum of size k, averages, anagram counts
Variable-SizeDepends on conditionLongest unique substring, minimum window

When Not to Use Sliding Window

  • Non-contiguous subsets (use DP or brute force).
  • Arbitrary reordering (use sorting or hashing).
  • Conditions that are not monotone over the window.

Syntax & Core Mechanics

Fixed-Size Template

c

/* Compute initial window sum for [0, k-1] */ long long window = 0; for (int i = 0; i < k; i++) window += arr[i]; long long best = window; /* Slide: subtract outgoing, add incoming */ for (int i = k; i < n; i++) { window += arr[i] - arr[i - k]; if (window > best) best = window; }

Variable-Size Template

c

int left = 0; /* Optional: state (freq map, sum, count) */ for (int right = 0; right < n; right++) { /* 1. Include arr[right] into state */ /* 2. While invariant violated, shrink from left */ while (/* invariant violated */) { /* remove arr[left] from state */ left++; } /* 3. Update best answer using [left, right] */ }

Key Invariant

For variable-size windows, we maintain:

All elements in [left, right] satisfy the problem’s condition, and right - left + 1 is the current candidate.

When the condition breaks, shrink left until the condition holds again.


Full Practical Code Example with Explanation

Below are six complete C programs covering the most-asked interview problems. Each is self-contained, C99/C11-compliant, and includes expected output.

Problem 1: Maximum Sum of Subarray of Size k (Easy)

c

#include <stdio.h> #include <limits.h> long long maxSumFixedK(const int arr[], int n, int k) { if (k <= 0 || n < k) return LLONG_MIN; long long window = 0; for (int i = 0; i < k; i++) window += arr[i]; long long best = window; for (int i = k; i < n; i++) { window += arr[i] - arr[i - k]; if (window > best) best = window; } return best; } int main(void) { int arr[] = {5, 2, -1, 0, 3}; int n = sizeof(arr) / sizeof(arr[0]); printf("%lld\n", maxSumFixedK(arr, n, 3)); /* 6 */ return 0; }

Expected output:

text

6

Time: O(n), Space: O(1)

Problem 2: Longest Substring Without Repeating Characters (Medium)

c

#include <stdio.h> int longestUnique(const char *s) { int lastSeen[256]; for (int i = 0; i < 256; i++) lastSeen[i] = -1; int left = 0, best = 0; for (int right = 0; s[right] != '\0'; right++) { unsigned char c = (unsigned char)s[right]; if (lastSeen[c] >= left) left = lastSeen[c] + 1; lastSeen[c] = right; int len = right - left + 1; if (len > best) best = len; } return best; } int main(void) { printf("%d\n", longestUnique("abcabcbb")); /* 3 */ printf("%d\n", longestUnique("bbbbb")); /* 1 */ printf("%d\n", longestUnique("pwwkew")); /* 3 */ return 0; }

Expected output:

text

3 1 3

Time: O(n), Space: O(1)

Problem 3: Longest Repeating Character Replacement (Medium)

Given a string and integer k, find the longest substring that can be turned into a single repeated character using at most k replacements.

c

#include <stdio.h> int characterReplacement(const char *s, int k) { int count[26] = {0}; int left = 0, maxCount = 0, best = 0; for (int right = 0; s[right] != '\0'; right++) { int idx = s[right] - 'A'; count[idx]++; if (count[idx] > maxCount) maxCount = count[idx]; /* window size = right - left + 1; replacements needed = window size - maxCount */ while ((right - left + 1) - maxCount > k) { count[s[left] - 'A']--; left++; } int len = right - left + 1; if (len > best) best = len; } return best; } int main(void) { printf("%d\n", characterReplacement("AABABBA", 1)); /* 4 */ printf("%d\n", characterReplacement("ABAB", 2)); /* 4 */ return 0; }

Expected output:

text

4 4

Time: O(n), Space: O(1)

Problem 4: Minimum Window Substring (Hard)

Find the smallest substring of s that contains all characters of t (with multiplicities).

c

#include <stdio.h> #include <string.h> #include <limits.h> void minWindow(const char *s, const char *t, char *result, int resultSize) { result[0] = '\0'; if (t[0] == '\0' || s[0] == '\0') return; int need[256] = {0}, have[256] = {0}; int required = 0; for (int i = 0; t[i] != '\0'; i++) { if (need[(unsigned char)t[i]] == 0) required++; need[(unsigned char)t[i]]++; } int left = 0, formed = 0; int bestLen = INT_MAX, bestL = -1; int sLen = (int)strlen(s); for (int right = 0; right < sLen; right++) { unsigned char c = (unsigned char)s[right]; have[c]++; if (need[c] > 0 && have[c] == need[c]) formed++; while (formed == required) { int len = right - left + 1; if (len < bestLen) { bestLen = len; bestL = left; } unsigned char lc = (unsigned char)s[left]; have[lc]--; if (need[lc] > 0 && have[lc] < need[lc]) formed--; left++; } } if (bestL != -1 && bestLen < resultSize) { memcpy(result, s + bestL, (size_t)bestLen); result[bestLen] = '\0'; } } int main(void) { char result[256]; minWindow("ADOBECODEBANC", "ABC", result, sizeof(result)); printf("%s\n", result); /* BANC */ minWindow("a", "a", result, sizeof(result)); printf("%s\n", result); /* a */ minWindow("a", "aa", result, sizeof(result)); printf("\"%s\"\n", result); /* "" */ return 0; }

Expected output:

text

BANC a ""

Time: O(|s| + |t|), Space: O(1)

Problem 5: Maximum Consecutive 1s with K Flips (Medium)

Given a binary array and k flips allowed, find the longest subarray of all 1s.

c

#include <stdio.h> int longestOnes(const int arr[], int n, int k) { int left = 0, zeros = 0, best = 0; for (int right = 0; right < n; right++) { if (arr[right] == 0) zeros++; while (zeros > k) { if (arr[left] == 0) zeros--; left++; } int len = right - left + 1; if (len > best) best = len; } return best; } int main(void) { int arr1[] = {1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0}; int arr2[] = {0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1}; printf("%d\n", longestOnes(arr1, 11, 2)); /* 6 */ printf("%d\n", longestOnes(arr2, 19, 3)); /* 10 */ return 0; }

Expected output:

text

6 10

Time: O(n), Space: O(1)

Problem 6: Count Distinct Elements in Every Window of Size K (Medium)

For each window of size k, count distinct elements.

c

#include <stdio.h> #include <stdlib.h> #define TABLE_SIZE 4096 typedef struct { int *keys; int *counts; int *occupied; int capacity; } FreqMap; static unsigned int hashFunc(int key, int cap) { return ((unsigned int)key) % (unsigned int)cap; } static FreqMap *mapCreate(int cap) { FreqMap *m = malloc(sizeof(FreqMap)); if (m == NULL) return NULL; m->keys = malloc((size_t)cap * sizeof(int)); m->counts = calloc((size_t)cap, sizeof(int)); m->occupied = calloc((size_t)cap, sizeof(int)); if (m->keys == NULL || m->counts == NULL || m->occupied == NULL) { free(m->keys); free(m->counts); free(m->occupied); free(m); return NULL; } m->capacity = cap; return m; } static void mapFree(FreqMap *m) { if (m) { free(m->keys); free(m->counts); free(m->occupied); free(m); } } static int mapAdd(FreqMap *m, int key) { unsigned int idx = hashFunc(key, m->capacity); int start = (int)idx; while (m->occupied[idx]) { if (m->keys[idx] == key) { m->counts[idx]++; return m->counts[idx]; } idx = (idx + 1) % (unsigned int)m->capacity; if ((int)idx == start) return -1; } m->keys[idx] = key; m->counts[idx] = 1; m->occupied[idx] = 1; return 1; } static void mapRemove(FreqMap *m, int key) { unsigned int idx = hashFunc(key, m->capacity); int start = (int)idx; while (m->occupied[idx]) { if (m->keys[idx] == key) { m->counts[idx]--; return; } idx = (idx + 1) % (unsigned int)m->capacity; if ((int)idx == start) return; } } static int mapDistinct(FreqMap *m) { int d = 0; for (int i = 0; i < m->capacity; i++) if (m->occupied[i] && m->counts[i] > 0) d++; return d; } void countDistinctInWindows(const int arr[], int n, int k) { FreqMap *m = mapCreate(TABLE_SIZE); if (m == NULL) return; for (int i = 0; i < k; i++) mapAdd(m, arr[i]); printf("%d ", mapDistinct(m)); for (int i = k; i < n; i++) { mapRemove(m, arr[i - k]); mapAdd(m, arr[i]); printf("%d ", mapDistinct(m)); } printf("\n"); mapFree(m); } int main(void) { int arr[] = {1, 2, 1, 3, 4, 2, 3}; int n = 7, k = 4; countDistinctInWindows(arr, n, k); /* 3 4 4 3 */ return 0; }

Expected output:

text

3 4 4 3

Time: O(n) average, Space: O(k)


Common Pitfalls, Edge Cases & Memory Considerations

1. Off-by-One in Window Size

The window [left, right] has size right - left + 1. Double-check inclusive bounds.

2. Non-Monotone Invariant

Sliding windows require the condition to monotonically improve as you shrink. Sum-with-negatives problems often violate this — use prefix sums instead.

3. Duplicate Handling in Frequency Maps

When shrinking, decrement counts; do not remove entries entirely (else your map’s occupied markers corrupt probes).

4. Initialization of the First Window

For fixed-size windows, initialize before entering the slide loop. Off-by-one here is the most common bug.

5. Integer Overflow

Use long long for sums and products.

6. Character Arrays and unsigned char

Negative char values (e.g., extended ASCII) index arrays with wraparound. Cast to unsigned char.

7. Empty Inputs

Always guard n <= 0 or s[0] == '\0'.

8. k > n or k = 0

Define and enforce semantics.

9. Variable Window When left > right

Some problems require resetting left = right when shrunk past the right boundary.

10. Memory Considerations

  • Fixed-size windows: O(1) space.
  • Variable-size with frequency map: O(k) or O(alphabet).
  • For substring problems, size frequency arrays to 256 (or larger for Unicode).
  • Free all dynamically allocated memory.

Summary & Best Practices

The Sliding Window Technique is a cornerstone of array and string interview problems. Mastering its two variants—fixed-size and variable-size—unlocks an entire family of linear-time solutions.

Key Takeaways

  • Two variants: fixed-size (constant k) and variable-size (condition-driven).
  • Each element enters and leaves the window at most once → O(n).
  • Invariant must be monotone: shrinking must restore validity.
  • Hash maps and frequency arrays integrate cleanly with the window.
  • Not every subarray problem is a sliding window problem.

Best Practices

  1. Identify the window type before writing code.
  2. Initialize the first window explicitly for fixed-size problems.
  3. Use long long for sums and large counters.
  4. Cast char to unsigned char before indexing arrays.
  5. Keep the invariant simple — one line that captures the goal.
  6. Prefer frequency arrays over hash maps for small alphabets.
  7. Free dynamic memory on all exit paths.
  8. Test with edge cases: empty, single element, k = 0, k = n, k > n.
  9. Verify with a brute-force solution for small inputs.
  10. Master the pattern, not just the specific problem — the interview will vary.

Recommended Practice List (from the source)

  • Easy: Maximum sum subarray of size k; Smallest window containing 0, 1, 2; Permutation substring; Strictly increasing subarrays; Remove consecutive characters.
  • Medium: Longest substring with distinct characters; Substrings with K Distinct; Maximum Consecutive 1s with K Flips; Maximum Fruits in Two Baskets; Minimum Window; Binary Subarray with Sum; Longest Repeating Character Replacement; Count Anagrams.
  • Hard: Maximum of Minimum for Every Window Size; Longest Substring with K Uniques; Minimum Window Substring; Largest Sum Subarray with At Least k Numbers.

Working through these problems with the templates above will solidify the pattern.

Learn to compute sum of all subarrays in C using naive O(n²) and optimal O(n) element contribution approaches. Master array algorithms.

Sum of All Subarrays in C: O(n) Contribution Method

Sum of All Subarrays in C: A Comprehensive Tutorial

Computing the sum of all possible subarrays of an array is a classic algorithmic problem. A subarray is a contiguous part of the array. This problem tests your understanding of array traversal, optimization techniques, and the element contribution method. Understanding this problem is essential for solving range-sum queries, prefix sum computations, and many dynamic programming problems.

This tutorial provides an in-depth exploration of computing the sum of all subarrays in C: naive nested-loop approach, optimized element contribution method, practical implementation, common pitfalls, and best practices.


Conceptual Introduction & Fundamentals

What is the Problem?

Given an integer array arr[], compute the sum of all possible subarrays.

Example:

text

Input: arr = [1, 4, 5, 3, 2] Output: 116

Understanding Subarrays:

text

[1], [1,4], [1,4,5], [1,4,5,3], [1,4,5,3,2] [4], [4,5], [4,5,3], [4,5,3,2] [5], [5,3], [5,3,2] [3], [3,2] [2]

Total = 116.

Why This Problem Matters

  • Prefix sums: Foundation for range query problems.
  • Element contribution: Powerful technique for many array problems.
  • Time-space trade-off: O(n²) to O(n) transformation.
  • Interview preparation: Common coding interview question.
  • Algorithm design: Teaches recognizing patterns and mathematical simplification.

Key Insight: Element Contribution

Instead of enumerating all subarrays, count how many subarrays include each element. For element at index i in an array of size n:

text

Number of subarrays containing arr[i] = (i + 1) × (n - i)
  • (i + 1) choices for the starting index (0 to i)
  • (n - i) choices for the ending index (i to n-1)

Total Sum = Σ arr[i] × (i + 1) × (n – i)

Approaches Overview

ApproachTime ComplexitySpace Complexity
Naive nested loopsO(n²)O(1)
Element contributionO(n)O(1)

Syntax & Core Mechanics

Approach 1: Naive Nested Loops

Iterate over all starting indices, extend to all ending indices, and accumulate sums.

c

#include <stdio.h> #include <limits.h> long long subarraySumNaive(const int arr[], int n) { if (n <= 0) return 0; long long result = 0; for (int i = 0; i < n; i++) { long long temp = 0; for (int j = i; j < n; j++) { temp += arr[j]; result += temp; } } return result; } int main(void) { int arr[] = {1, 4, 5, 3, 2}; int n = sizeof(arr) / sizeof(arr[0]); printf("Sum of all subarrays: %lld\n", subarraySumNaive(arr, n)); return 0; }

Expected output:

text

Sum of all subarrays: 116

Time: O(n²), Space: O(1)

Approach 2: Element Contribution Method

Use the formula arr[i] × (i + 1) × (n - i) for each element.

c

#include <stdio.h> long long subarraySumContribution(const int arr[], int n) { if (n <= 0) return 0; long long result = 0; for (int i = 0; i < n; i++) { result += (long long)arr[i] * (i + 1) * (n - i); } return result; } int main(void) { int arr[] = {1, 4, 5, 3, 2}; int n = sizeof(arr) / sizeof(arr[0]); printf("Sum of all subarrays: %lld\n", subarraySumContribution(arr, n)); return 0; }

Expected output:

text

Sum of all subarrays: 116

Time: O(n), Space: O(1)

Step-by-Step for [1, 4, 5, 3, 2]

text

i=0: 1 × 1 × 5 = 5 i=1: 4 × 2 × 4 = 32 i=2: 5 × 3 × 3 = 45 i=3: 3 × 4 × 2 = 24 i=4: 2 × 5 × 1 = 10 Total = 5 + 32 + 45 + 24 + 10 = 116

Verification Against Naive

For [1, 2, 3]:

text

Element contribution: i=0: 1 × 1 × 3 = 3 i=1: 2 × 2 × 2 = 8 i=2: 3 × 3 × 1 = 9 Total = 20 Naive verification: [1]=1, [1,2]=3, [1,2,3]=6, [2]=2, [2,3]=5, [3]=3 Total = 1+3+6+2+5+3 = 20 ✓

Full Practical Code Example with Explanation

This program demonstrates both approaches with verification, performance comparison, and edge cases.

Program: Sum of All Subarrays Comparison

c

/** * sum_of_all_subarrays.c * Computes the sum of all subarrays. * Compares naive and element contribution approaches. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <time.h> #define MAX_LINE_LEN 100 #define MAX_SIZE 100000 /* Function prototypes */ long long subarraySumNaive(const int arr[], int n); long long subarraySumContribution(const int arr[], int n); int readInteger(const char *prompt, int *outValue); void printArray(const int arr[], int n); void demonstrateApproaches(void); void performanceComparison(void); void demonstrateEdgeCases(void); int main(void) { int choice; char buffer[MAX_LINE_LEN]; printf("=== Sum of All Subarrays Demo ===\n"); while (1) { printf("\n--- Menu ---\n"); printf("1. Demonstrate with Sample Arrays\n"); printf("2. Enter Custom Array\n"); printf("3. Performance Comparison\n"); printf("4. Edge Cases\n"); printf("5. Exit\n"); printf("Enter choice: "); fflush(stdout); if (fgets(buffer, sizeof(buffer), stdin) == NULL) { fprintf(stderr, "Error reading choice.\n"); return EXIT_FAILURE; } choice = atoi(buffer); switch (choice) { case 1: demonstrateApproaches(); break; case 2: { int arr[MAX_SIZE]; int n; if (readInteger("Enter array size (1-100000): ", &n) != 0) { fprintf(stderr, "Invalid size.\n"); break; } if (n < 1 || n > MAX_SIZE) { printf("Size must be 1-%d.\n", MAX_SIZE); break; } printf("Enter %d elements:\n", n); for (int i = 0; i < n; i++) { char prompt[50]; snprintf(prompt, sizeof(prompt), " Element %d: ", i); if (readInteger(prompt, &arr[i]) != 0) { fprintf(stderr, "Invalid input.\n"); n = i; break; } } printf("\nArray: "); printArray(arr, n); long long naive = subarraySumNaive(arr, n); long long contrib = subarraySumContribution(arr, n); printf("Naive result: %lld\n", naive); printf("Contribution result: %lld\n", contrib); printf("Verification: %s\n", (naive == contrib) ? "PASS" : "FAIL"); break; } case 3: performanceComparison(); break; case 4: demonstrateEdgeCases(); break; case 5: printf("Exiting.\n"); return EXIT_SUCCESS; default: printf("Invalid choice. Please try again.\n"); break; } } return EXIT_SUCCESS; } /* Naive approach: O(n^2) */ long long subarraySumNaive(const int arr[], int n) { if (n <= 0) return 0; long long result = 0; for (int i = 0; i < n; i++) { long long temp = 0; for (int j = i; j < n; j++) { temp += arr[j]; result += temp; } } return result; } /* Element contribution: O(n) */ long long subarraySumContribution(const int arr[], int n) { if (n <= 0) return 0; long long result = 0; for (int i = 0; i < n; i++) { result += (long long)arr[i] * (i + 1) * (n - i); } return result; } /* Prints array */ void printArray(const int arr[], int n) { printf("["); for (int i = 0; i < n; i++) { printf("%d", arr[i]); if (i < n - 1) printf(", "); } printf("]\n"); } /* Demonstrates both approaches */ void demonstrateApproaches(void) { printf("\n=== Sample Arrays ===\n"); int arr1[] = {1, 4, 5, 3, 2}; int n1 = sizeof(arr1) / sizeof(arr1[0]); printf("\nArray 1: "); printArray(arr1, n1); printf("Naive: %lld\n", subarraySumNaive(arr1, n1)); printf("Contribution: %lld\n", subarraySumContribution(arr1, n1)); int arr2[] = {1, 2, 3, 4}; int n2 = sizeof(arr2) / sizeof(arr2[0]); printf("\nArray 2: "); printArray(arr2, n2); printf("Naive: %lld\n", subarraySumNaive(arr2, n2)); printf("Contribution: %lld\n", subarraySumContribution(arr2, n2)); int arr3[] = {1, 2, 3}; int n3 = sizeof(arr3) / sizeof(arr3[0]); printf("\nArray 3: "); printArray(arr3, n3); printf("Naive: %lld\n", subarraySumNaive(arr3, n3)); printf("Contribution: %lld\n", subarraySumContribution(arr3, n3)); int arr4[] = {5}; int n4 = sizeof(arr4) / sizeof(arr4[0]); printf("\nArray 4 (single): "); printArray(arr4, n4); printf("Naive: %lld\n", subarraySumNaive(arr4, n4)); printf("Contribution: %lld\n", subarraySumContribution(arr4, n4)); } /* Performance comparison */ void performanceComparison(void) { printf("\n=== Performance Comparison (n = 20000) ===\n"); int n = 20000; int *arr = malloc(n * sizeof(int)); if (arr == NULL) { fprintf(stderr, "Memory allocation failed.\n"); return; } for (int i = 0; i < n; i++) { arr[i] = (i % 100) + 1; } clock_t start, end; double timeTaken; /* Naive approach */ start = clock(); long long naiveResult = subarraySumNaive(arr, n); end = clock(); timeTaken = ((double)(end - start)) / CLOCKS_PER_SEC * 1000.0; printf("Naive (O(n^2)): Result = %lld, Time = %.3f ms\n", naiveResult, timeTaken); /* Contribution approach */ start = clock(); long long contribResult = subarraySumContribution(arr, n); end = clock(); timeTaken = ((double)(end - start)) / CLOCKS_PER_SEC * 1000.0; printf("Contribution (O(n)): Result = %lld, Time = %.3f ms\n", contribResult, timeTaken); printf("\nVerification: %s\n", (naiveResult == contribResult) ? "PASS" : "FAIL"); free(arr); } /* Demonstrates edge cases */ void demonstrateEdgeCases(void) { printf("\n=== Edge Cases ===\n"); /* Case 1: Empty array */ int arr1[] = {}; printf("Case 1: Empty array\n"); printf(" Sum: %lld\n", subarraySumContribution(arr1, 0)); /* Case 2: Single element */ int arr2[] = {42}; printf("\nCase 2: Single element\n"); printf(" Array: "); printArray(arr2, 1); printf(" Sum: %lld\n", subarraySumContribution(arr2, 1)); /* Case 3: Two elements */ int arr3[] = {3, 7}; printf("\nCase 3: Two elements\n"); printf(" Array: "); printArray(arr3, 2); printf(" Sum: %lld\n", subarraySumContribution(arr3, 2)); /* Case 4: All same elements */ int arr4[] = {5, 5, 5, 5}; printf("\nCase 4: All same elements\n"); printf(" Array: "); printArray(arr4, 4); printf(" Sum: %lld\n", subarraySumContribution(arr4, 4)); /* Case 5: Negative numbers */ int arr5[] = {1, -2, 3, -4, 5}; printf("\nCase 5: Negative numbers\n"); printf(" Array: "); printArray(arr5, 5); printf(" Sum: %lld\n", subarraySumContribution(arr5, 5)); /* Case 6: All negatives */ int arr6[] = {-1, -2, -3}; printf("\nCase 6: All negatives\n"); printf(" Array: "); printArray(arr6, 3); printf(" Sum: %lld\n", subarraySumContribution(arr6, 3)); /* Case 7: Large values (overflow check) */ int arr7[] = {100000, 200000, 300000}; printf("\nCase 7: Large values\n"); printf(" Array: "); printArray(arr7, 3); printf(" Sum: %lld (long long)\n", subarraySumContribution(arr7, 3)); } /* Reads an integer safely */ int readInteger(const char *prompt, int *outValue) { char buffer[MAX_LINE_LEN]; char *endPtr; long val; printf("%s", prompt); fflush(stdout); if (fgets(buffer, sizeof(buffer), stdin) == NULL) { return -1; } errno = 0; val = strtol(buffer, &endPtr, 10); if (endPtr == buffer || (*endPtr != '\n' && *endPtr != '\0')) { return -1; } if (errno == ERANGE || val < -2147483647 - 1 || val > 2147483647) { return -1; } *outValue = (int)val; return 0; }

Explanation of Approaches

  1. Naive: Uses nested loops to enumerate all subarrays; O(n²).
  2. Contribution: Uses formula arr[i] × (i+1) × (n-i); O(n).
  3. Overflow protection: Uses long long for the sum.

Expected Output (sample run)

text

=== Sum of All Subarrays Demo === --- Menu --- 1. Demonstrate with Sample Arrays 2. Enter Custom Array 3. Performance Comparison 4. Edge Cases 5. Exit Enter choice: 1 === Sample Arrays === Array 1: [1, 4, 5, 3, 2] Naive: 116 Contribution: 116 Array 2: [1, 2, 3, 4] Naive: 50 Contribution: 50 Array 3: [1, 2, 3] Naive: 20 Contribution: 20 Array 4 (single): [5] Naive: 5 Contribution: 5 --- Menu --- ... Enter choice: 3 === Performance Comparison (n = 20000) === Naive (O(n^2)): Result = 1308533334000, Time = 812.456 ms Contribution (O(n)): Result = 1308533334000, Time = 0.089 ms Verification: PASS --- Menu --- ... Enter choice: 4 === Edge Cases === Case 1: Empty array Sum: 0 Case 2: Single element Array: [42] Sum: 42 Case 3: Two elements Array: [3, 7] Sum: 20 Case 4: All same elements Array: [5, 5, 5, 5] Sum: 100 Case 5: Negative numbers Array: [1, -2, 3, -4, 5] Sum: 15 Case 6: All negatives Array: [-1, -2, -3] Sum: -20 Case 7: Large values Array: [100000, 200000, 300000] Sum: 1400000000 (long long)

Common Pitfalls, Edge Cases & Memory Considerations

1. Integer Overflow

The sum of all subarrays grows as O(n³) × max_value, easily exceeding int.

c

int result = 0; /* BUG: overflows quickly */ long long result = 0; /* Correct */

Solution: Use long long for the result and intermediate calculations.

2. Casting Before Multiplication

Without casting, arr[i] * (i+1) * (n-i) can overflow even if the result fits in long long.

c

result += (long long)arr[i] * (i + 1) * (n - i); /* Correct */

3. Empty Array

Return 0 for empty arrays.

c

if (n <= 0) return 0;

4. Single Element

The only subarray is the element itself.

c

int arr[] = {42}; /* Sum = 42 */

5. Negative Numbers

Negative values work correctly; results can be negative.

c

int arr[] = {-1, -2, -3}; /* Sum = -20 */

6. Off-by-One in Formula

The formula is (i + 1) × (n - i) for 0-based index i.

c

result += arr[i] * (i + 1) * (n - i); /* Correct */

7. Assuming Subarrays are Non-Empty

By definition, subarrays are non-empty contiguous segments.

8. Very Large Arrays

For n = 10⁶, even long long may overflow if values are large.

Solution: Use modular arithmetic or __int128 (GCC/Clang extension).

9. Performance of Naive

Naive O(n²) is unusable for n > 10000.

Solution: Use the O(n) contribution approach.

10. Memory Considerations

  • Both approaches use O(1) extra space.
  • No dynamic allocation required.
  • Use long long for results.
  • Contribution approach is preferred for large arrays.

Summary & Best Practices

Computing the sum of all subarrays is elegantly solved using the element contribution method in O(n) time. Each element arr[i] contributes arr[i] × (i + 1) × (n - i) to the total.

Key Takeaways

  • Subarray = contiguous part of an array.
  • Number of subarrays = n × (n + 1) / 2.
  • Element arr[i] appears in (i + 1) × (n - i) subarrays.
  • Naive approach: O(n²) time.
  • Contribution approach: O(n) time, O(1) space.
  • Use long long to prevent overflow.

Best Practices

  1. Use the contribution approach for O(n) time.
  2. Use long long for results and intermediate values.
  3. Cast before multiplication to prevent overflow.
  4. Handle empty arrays and single elements.
  5. Test with negative values and zeros.
  6. Verify with naive approach during testing.
  7. Avoid naive O(n²) for large arrays.
  8. Document the formula in comments.
  9. Consider modular arithmetic for very large sums.
  10. Profile performance for large arrays.

By mastering this problem, you’ll understand the element contribution technique, which is widely applicable to range-sum and prefix-sum problems.