[Easy] 455. Assign Cookies
[Easy] 455. Assign Cookies
Problem Statement
Assume you are an awesome parent and want to give your children some cookies. But, you should give each child at most one cookie.
Each child i has a greed factor g[i], which is the minimum size of a cookie that the child will be content with; and each cookie j has a size s[j]. If s[j] >= g[i], we can assign the cookie j to the child i, and the child i will be content. Your goal is to maximize the number of your content children and output the maximum number.
Examples
Example 1:
Input: g = [1,2,3], s = [1,1]
Output: 1
Explanation: You have 3 children and 2 cookies. The greed factors of 3 children are 1, 2, 3.
And even though you have 2 cookies, since their size is both 1, you could only make the child whose greed factor is 1 content.
You need to output 1.
Example 2:
Input: g = [1,2], s = [1,2,3]
Output: 2
Explanation: You have 2 children and 3 cookies. The greed factors of 2 children are 1, 2.
You have 3 cookies and their sizes are big enough to gratify all of the children,
You need to output 2.
Constraints
1 <= g.length <= 3 * 10^40 <= s.length <= 3 * 10^41 <= g[i], s[j] <= 2^31 - 1
Clarification Questions
Before diving into the solution, here are 5 important clarifications and assumptions to discuss during an interview:
-
Assignment rule: Can one cookie satisfy multiple children? (Assumption: No - one cookie can only satisfy one child)
-
Cookie size requirement: What size cookie is needed for a child? (Assumption: Cookie size must be >= child’s greed factor)
-
Optimization goal: What are we optimizing for? (Assumption: Maximize the number of satisfied children - greedy approach)
-
Cookie reuse: Can we use the same cookie multiple times? (Assumption: No - each cookie can only be used once)
-
Ordering: Does the order of children or cookies matter? (Assumption: No - we can assign in any order, but sorting helps optimize)
Interview Deduction Process (10 minutes)
Step 1: Brute-Force Approach (2 minutes)
Initial Thought: “I need to assign cookies to children. Let me try all possible assignments.”
Naive Solution: Try all possible cookie-to-child assignments, count valid ones. Use nested loops or backtracking.
Complexity: O(n × m) or exponential time, O(1) space
Issues:
- Very inefficient for large inputs
- Doesn’t leverage greedy property
- Overcomplicated for this problem
Step 2: Semi-Optimized Approach (3 minutes)
Insight: “I should match smallest cookie to smallest child first. This is a greedy approach.”
Improved Solution: Sort both arrays. Use two pointers to match smallest available cookie to smallest unsatisfied child greed factor.
Complexity: O(n log n + m log m) time, O(1) space
Improvements:
- Greedy matching is optimal
- Sorting enables efficient matching
- Two-pointer technique is clean
- Handles all cases correctly
Step 3: Optimized Solution (5 minutes)
Final Optimization: “The greedy two-pointer approach is already optimal. Sorting is necessary for correctness.”
Best Solution: Sort both arrays, use greedy matching with two pointers. This maximizes number of satisfied children.
Key Realizations:
- Greedy approach is optimal for this problem
- Sorting enables efficient O(n + m) matching after sort
- Two-pointer technique is elegant
- O(n log n) sorting dominates time complexity
Solution Approach
This is a classic greedy algorithm problem. The key insight is to use a greedy strategy: assign the smallest cookie that satisfies each child’s greed factor, starting with the child with the smallest greed factor.
Key Insights:
- Sorting: Sort both arrays to process in order
- Greedy Choice: Always assign the smallest cookie that satisfies a child
- Two Pointers: Use two pointers to match children with cookies efficiently
- Optimal: This greedy approach maximizes the number of content children
Algorithm:
- Sort: Sort
g(children’s greed factors) ands(cookie sizes) - Match: Use two pointers to match smallest cookie to smallest child
- Count: Count successful assignments
Solution
Solution 1: Two Pointers with Conditional Advancement
class Solution:
def findContentChildren(self, g, s):
g.sort()
s.sort()
count = 0
i = 0
j = 0
while i < len(g) and j < len(s):
if s[j] >= g[i]:
count += 1
i += 1
j += 1
return count
Solution 2: Two Pointers with While Loop for Cookie
class Solution:
def findContentChildren(self, g, s):
g.sort()
s.sort()
num_of_children, num_of_cookies = len(g), len(s)
count = 0
j = 0
for i in range(num_of_children):
while j < num_of_cookies and g[i] > s[j]:
j += 1
if j < num_of_cookies:
count += 1
j += 1
else:
break
return count
Algorithm Explanation:
Solution 1:
- Sort Arrays (Lines 4-5):
- Sort
gin ascending order (children’s greed factors) - Sort
sin ascending order (cookie sizes)
- Sort
- Two Pointers Matching (Lines 6-14):
- Initialize:
ifor children,jfor cookies,countfor assignments - While both arrays have elements:
- If cookie satisfies child:
s[j] >= g[i]- Increment
count - Move to next child (
i++) - Move to next cookie (
j++)
- Increment
- Else: Cookie too small, skip it (
j++)
- If cookie satisfies child:
- Initialize:
Solution 2:
-
Sort Arrays (Lines 4-5): Same as Solution 1
-
For Each Child (Lines 7-13):
- Skip small cookies: Use
whileloop to skip cookies smaller than child’s greed - Check bounds: Ensure
j < numOfCookiesafter skipping - Assign if valid: If cookie found, increment count
- Advance both: Move to next child and cookie
- Skip small cookies: Use
Example Walkthrough:
Example 1: g = [1,2,3], s = [1,1]
After sorting:
g = [1, 2, 3]
s = [1, 1]
Solution 1 Execution:
Initial: i=0, j=0, count=0
Step 1: s[0]=1 >= g[0]=1 ✓
count=1, i=1, j=1
Step 2: s[1]=1 < g[1]=2 ✗
j=2 (out of bounds)
Result: count=1
Solution 2 Execution:
Initial: i=0, j=0, count=0
i=0: g[0]=1
while: j=0, s[0]=1 >= 1, no skip
j=0 < 2 ✓, count=1
i=1, j=1
i=1: g[1]=2
while: j=1, s[1]=1 < 2, j=2 (out of bounds)
j=2 >= 2 ✗, no assignment
Result: count=1
Example 2: g = [1,2], s = [1,2,3]
After sorting:
g = [1, 2]
s = [1, 2, 3]
Solution 1 Execution:
Initial: i=0, j=0, count=0
Step 1: s[0]=1 >= g[0]=1 ✓
count=1, i=1, j=1
Step 2: s[1]=2 >= g[1]=2 ✓
count=2, i=2 (out of bounds)
Result: count=2
Solution 2 Execution:
Initial: i=0, j=0, count=0
i=0: g[0]=1
while: j=0, s[0]=1 >= 1, no skip
j=0 < 3 ✓, count=1
i=1, j=1
i=1: g[1]=2
while: j=1, s[1]=2 >= 2, no skip
j=1 < 3 ✓, count=2
i=2 (out of bounds)
Result: count=2
Algorithm Breakdown
Why Greedy Works
The greedy strategy is optimal because:
- Smallest First: Assign smallest cookie to smallest child maximizes remaining options
- No Regret: If we skip a cookie for a child, we can’t use it later (each child gets at most one)
- Optimal Substructure: After assigning a cookie, the subproblem (remaining children and cookies) is independent
Why Sorting is Necessary
Without sorting, we might:
- Assign a large cookie to a child with small greed factor
- Miss opportunities to satisfy more children
- Need to check all combinations (O(n²))
With sorting:
- Process in order (smallest to largest)
- Greedy choice is optimal
- Linear time matching
Comparison of Solutions
Solution 1:
- Advancement: Cookie pointer advances in both branches
- Logic: Clear if-else structure
- Efficiency: Both pointers advance optimally
Solution 2:
- Advancement: Cookie pointer skips multiple small cookies at once
- Logic: Uses while loop to skip cookies
- Efficiency: Same time complexity, slightly different style
Both solutions have the same time complexity and produce the same result.
Time & Space Complexity
- Time Complexity:
-
Sorting: O(g log g + s log s) where g = g , s = s - Matching: O(g + s) - each element visited at most once
- Total: O(g log g + s log s)
-
- Space Complexity: O(1) - only using a few variables (excluding input arrays)
Key Points
- Greedy Algorithm: Always make locally optimal choice
- Sorting: Essential for greedy approach to work
- Two Pointers: Efficient matching technique
- Optimal: Greedy strategy maximizes number of content children
- Simple: Straightforward implementation
Alternative Approaches
Approach 1: Greedy with Sorting (Current Solutions)
- Time: O(g log g + s log s)
- Space: O(1)
- Best for: General case, optimal solution
Approach 2: Brute Force (Check All Combinations)
- Time: O(g × s)
- Space: O(1)
- Use when: Arrays are very small (not practical)
Approach 3: Binary Search (For Each Child)
- Time: O(g log s)
- Space: O(1)
- Use when: Cookies array is much larger than children array
Edge Cases
- No cookies:
s = []→ return 0 - No children:
g = []→ return 0 - All cookies too small:
g = [5,6,7],s = [1,2,3]→ return 0 - All children satisfied:
g = [1,2],s = [3,4,5]→ return 2 - Single child, single cookie:
g = [1],s = [1]→ return 1
Related Problems
- 135. Candy - Greedy with constraints
- 406. Queue Reconstruction by Height - Greedy with sorting
- 452. Minimum Number of Arrows to Burst Balloons - Interval greedy
- 435. Non-overlapping Intervals - Greedy interval selection
Tags
Array, Greedy, Sorting, Two Pointers, Easy