Greedy vs DP How to Know Which to Apply in DSA Typescript - Complexity Comparison
When deciding between Greedy and Dynamic Programming (DP), understanding how their time costs grow helps us choose the right method.
We want to know which approach runs faster as the problem size grows.
Analyze the time complexity of these two simplified approaches.
// Greedy approach example
function greedySolution(items: number[]): number {
let total = 0;
for (const item of items) {
if (item > 0) total += item;
}
return total;
}
// DP approach example
function dpSolution(items: number[]): number {
const dp = new Array(items.length + 1).fill(0);
for (let i = 1; i <= items.length; i++) {
dp[i] = Math.max(dp[i - 1], dp[i - 1] + items[i - 1]);
}
return dp[items.length];
}
The greedy function sums positive items quickly. The DP function considers combinations to find the best sum.
Look at the loops and repeated steps in each approach.
- Greedy primary operation: One loop over all items.
- Greedy loop count: Runs once for each item (n times).
- DP primary operation: One loop filling the dp array.
- DP loop count: Also runs once for each item (n times), but does extra work inside.
Both methods loop through the input once, but DP does more work per step.
| Input Size (n) | Greedy Approx. Operations | DP Approx. Operations |
|---|---|---|
| 10 | ~10 simple checks | ~10 calculations and comparisons |
| 100 | ~100 simple checks | ~100 calculations and comparisons |
| 1000 | ~1000 simple checks | ~1000 calculations and comparisons |
Pattern observation: Both grow linearly, but DP does more work per item.
Time Complexity: O(n) for both Greedy and DP in this example.
This means both take time proportional to the number of items, but DP usually has more steps per item.
[X] Wrong: "Greedy is always faster and better than DP."
[OK] Correct: Greedy is faster but only works when local choices lead to a global best. DP handles complex cases but may be slower.
Knowing when to pick Greedy or DP shows you understand problem patterns and efficiency, a key skill interviewers look for.
"What if the DP solution used nested loops to compare all pairs? How would the time complexity change?"
Practice
Solution
Step 1: Understand greedy choice property
A greedy algorithm works when choosing the best option at each step leads to a global optimum.Step 2: Check optimal substructure
Optimal substructure means the optimal solution can be built from optimal solutions of subproblems.Final Answer:
When the problem has the greedy choice property and optimal substructure -> Option AQuick Check:
Greedy = greedy choice + optimal substructure [OK]
- Confusing overlapping subproblems with greedy applicability
- Using greedy when problem needs full exploration
- Ignoring optimal substructure requirement
Solution
Step 1: Understand memo type for DP
Memoization stores results with keys, so Record is suitable.Step 2: Check syntax correctness
const memo: Record = {}; correctly declares an empty object with number keys and values.Final Answer:
const memo: Record = {}; -> Option CQuick Check:
Memo object uses Record type [OK]
- Using var instead of const or let
- Incorrect type assertion for memo
- Using Map without type parameters
function maxSum(arr: number[]): number {
let sum = 0;
for (let i = 0; i < arr.length; i++) {
if (arr[i] > 0) sum += arr[i];
}
return sum;
}
console.log(maxSum([-1, 2, 3, -5, 4]));
What is the output?Solution
Step 1: Trace the loop and sum positive numbers
Positive numbers are 2, 3, and 4. Sum = 2 + 3 + 4 = 9.Step 2: Confirm return value
The function returns sum = 9, so console.log prints 9.Final Answer:
9 -> Option AQuick Check:
Sum positives = 9 [OK]
- Adding negative numbers mistakenly
- Returning zero instead of sum
- Confusing output with array length
function fib(n: number, memo: Record = {}): number {
if (n <= 1) return n;
if (memo[n]) return memo[n];
memo[n] = fib(n - 1, memo) + fib(n - 2, memo);
return memo[n];
}
console.log(fib(5));Solution
Step 1: Analyze memo check condition
Checking 'if (memo[n])' fails when memo[n] is 0, which is falsy.Step 2: Correct memo check
Use 'if (memo[n] !== undefined)' to correctly detect stored values including zero.Final Answer:
The memo check should be 'if (memo[n] !== undefined)' to handle zero -> Option DQuick Check:
Memo check must handle zero values [OK]
- Using truthy check for memo causing wrong cache hits
- Wrong base case for Fibonacci
- Incorrect recursive call directions
interface Task {
duration: number;
deadline: number;
}
function scheduleTasks(tasks: Task[]): number {
// Implementation needed
}Solution
Step 1: Understand problem goal
Maximize number of tasks completed before deadlines means scheduling tasks efficiently.Step 2: Identify best approach
Greedy algorithm sorting by earliest deadline ensures maximum tasks fit before deadlines.Final Answer:
Use a greedy algorithm sorting tasks by earliest deadline to maximize count -> Option BQuick Check:
Earliest deadline first greedy maximizes tasks [OK]
- Trying all subsets with DP causing inefficiency
- Sorting by longest duration wastes time
- Ignoring deadlines in scheduling
Ready to prove it?
Pass the test and this pattern moves unknown
