LeetCode #455 Easy

Assign Cookies

Child i is content if they get a cookie of size at least their greed g[i]. Each child gets at most one cookie. Maximize the number of content children.

greedysortingtwo pointers
Open on LeetCode ↗
02

Intuition

Sort both lists and hand the smallest useful cookie to the least greedy child. A big cookie spent on an easily-pleased kid is a waste — matching small with small keeps the large cookies for the kids who actually need them.

How to spot this pattern

Two sorted lists walked with two pointers — the exchange-argument greedy. Give the smallest adequate cookie to the least demanding child: any other assignment can be swapped for this one without losing a match, so greedy is provably optimal. That swap argument is the standard way to prove a greedy is safe.

03

Approach

1

Why greedy is safe here

Suppose an optimal solution gives the least greedy unfed child a bigger cookie than necessary. Swap it with the smallest cookie that satisfies them — nothing breaks, and the bigger cookie is freed for someone greedier. Repeating this argument turns any optimal solution into the greedy one, so greedy is optimal.

2

Two pointers over two sorted lists

Sort g (greed) and s (cookies). Walk the cookies smallest-first with a pointer child into the greed list: if the current cookie satisfies g[child], feed them and advance child; otherwise the cookie is too small for everyone remaining (they're sorted!) — discard it and try the next.

3

The child pointer is the answer

Every advance of child is one content kid, and no cookie is ever reconsidered. One pass after sorting: O(n log n + m log m) time, O(1) extra space. child ends as the count.

04

Solution & live demo

1class Solution:
2 def findContentChildren(self, g, s):
3 g.sort()
4 s.sort()
5 child = 0
6 for cookie in s:
7 if child < len(g) and g[child] <= cookie:
8 child += 1
9 return child
05

Common pitfalls

Assigning the largest cookies first

✗ Wrong
g.sort(reverse=True)
s.sort(reverse=True)
✓ Right
g.sort()
s.sort()

Spending a big cookie on a child a small one would satisfy wastes capacity that a greedier child may need. Ascending order guarantees each cookie goes to the least demanding child it can still satisfy.

Advancing the child pointer on a failed match

✗ Wrong
for cookie in s:
    if g[child] <= cookie: child += 1
    else: child += 1
✓ Right
if child < len(g) and g[child] <= cookie:
    child += 1

A child that this cookie can't satisfy should stay in line for a bigger one, not be skipped. Only a successful assignment advances the child.

Indexing past the end of the children list

✗ Wrong
if g[child] <= cookie:
✓ Right
if child < len(g) and g[child] <= cookie:

With more cookies than children the loop keeps running after every child is served, and g[child] goes out of range. The bound check has to come first.

06

Edge cases

No cookies, or no children

The loop body never feeds anyone — return 0.

All cookies too small

Every comparison fails; child never advances; answer 0.

More cookies than children

Once child == len(g) everyone is fed — break early; extra cookies are irrelevant.

07

Complexity

Time
O(n log n + m log m)
Space
O(1)
Dominated by the two sorts; the merge walk itself is linear.