Divide and Conquer Strategy and Recurrence Relations in DSA Typescript - Time & Space Complexity
Divide and conquer breaks a big problem into smaller parts, solves each part, then combines results.
We want to know how the time to solve grows as the problem size grows.
Analyze the time complexity of this divide and conquer example.
function divideAndConquer(arr: number[], start: number, end: number): number {
if (start > end) return 0;
if (start === end) return arr[start];
const mid = Math.floor((start + end) / 2);
const left = divideAndConquer(arr, start, mid);
const right = divideAndConquer(arr, mid + 1, end);
return left + right;
}
This function splits the array into halves, sums each half recursively, then adds the results.
Look for repeated work in the code.
- Primary operation: Recursive calls splitting the array into halves.
- How many times: Each call splits the problem into two smaller parts until size 1.
Each step splits the problem in two, doing work on smaller parts.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 19 calls (splits and sums) |
| 100 | About 199 calls |
| 1000 | About 1999 calls |
Pattern observation: The number of calls grows linearly with n.
Time Complexity: O(n)
This means the total work grows linearly with the size of the input array.
[X] Wrong: "Because it splits the problem in half each time, the time is O(log n)."
[OK] Correct: Each level of splitting does work on all elements, so total work adds up to O(n), not just O(log n).
Understanding how divide and conquer breaks problems down and how to analyze their time helps you solve many common coding challenges confidently.
What if the function combined results with a loop over the entire array segment instead of just adding two values? How would the time complexity change?
Practice
Divide and Conquer strategy in algorithms?Solution
Step 1: Understand the divide and conquer approach
It splits a big problem into smaller parts that are easier to solve.Step 2: Combine the solutions of smaller parts
After solving subproblems, their results are merged to get the final answer.Final Answer:
Break the problem into smaller subproblems, solve them independently, then combine results -> Option AQuick Check:
Divide and conquer = split, solve, combine [OK]
- Confusing divide and conquer with brute force
- Thinking it uses only loops without recursion
- Mixing it up with dynamic programming
Solution
Step 1: Recall Merge Sort process
Merge Sort splits array into two halves, sorts each half, then merges.Step 2: Write recurrence relation
It calls itself twice on half size (2T(n/2)) plus merging cost O(n).Final Answer:
T(n) = 2T(n/2) + O(n) -> Option BQuick Check:
Merge Sort recurrence = 2T(n/2) + n [OK]
- Using T(n-1) instead of T(n/2)
- Confusing merge cost with recursive calls
- Choosing cubic or quadratic terms incorrectly
function findMax(arr: number[], left: number, right: number): number {
if (left === right) return arr[left];
const mid = Math.floor((left + right) / 2);
const maxLeft = findMax(arr, left, mid);
const maxRight = findMax(arr, mid + 1, right);
return maxLeft > maxRight ? maxLeft : maxRight;
}
const array = [3, 5, 1, 8, 2];
console.log(findMax(array, 0, array.length - 1));Solution
Step 1: Understand the function logic
The function splits the array into halves recursively and compares max values.Step 2: Trace the recursive calls on array [3,5,1,8,2]
Max in left half [3,5,1] is 5; max in right half [8,2] is 8; final max is 8.Final Answer:
8 -> Option CQuick Check:
Max element found by divide and conquer = 8 [OK]
- Returning min instead of max
- Incorrect mid calculation causing infinite recursion
- Mixing indices causing wrong subarray
T(n) = 2T(n/2) + O(n^2)This recurrence is supposed to represent the time complexity of a divide and conquer algorithm similar to Merge Sort.
Solution
Step 1: Analyze the merging cost in divide and conquer
In Merge Sort-like algorithms, merging two halves takes O(n) time, not O(n^2).Step 2: Correct the recurrence relation
Replace O(n^2) with O(n) to reflect the linear merging cost.Final Answer:
Change O(n^2) to O(n) because merging takes linear time -> Option AQuick Check:
Merging cost = O(n), not O(n^2) [OK]
- Assuming merging is quadratic
- Changing recursive calls incorrectly
- Ignoring the cost of merging step
T(n) = 3T(n/3) + n, what is the time complexity of the algorithm using the Master Theorem?Solution
Step 1: Identify parameters for Master Theorem
Here, a=3, b=3, f(n)=n. Calculate log_b(a) = log_3(3) = 1.Step 2: Compare f(n) with n^{log_b(a)}
f(n) = n and n^{log_b(a)} = n^1 = n, so f(n) = Theta(n^{log_b(a)}).Step 3: Apply Master Theorem case 2
When f(n) = Theta(n^{log_b(a)}), T(n) = Theta(n^{log_b(a)} log n) = Theta(n log n).Final Answer:
O(n log n) -> Option DQuick Check:
Master Theorem case 2 gives O(n log n) [OK]
- Ignoring the log factor in case 2
- Confusing log base or parameters a and b
- Choosing linear time incorrectly
Ready to prove it?
Pass the test and this pattern moves unknown
