A school store has a SORTED list of prices and a fixed budget: can two prices spend it exactly without testing every pair? And what is the longest run of days whose total training stays under a limit? Both become LINEAR when two indices move forward with a clear rule. We build it as a short ladder of executable demos with a Notice, then a full stdin solver.
-
Move two pointers inward on a sorted list to find a pair with a given sum.
-
Track the closest sum while the pointers converge.
-
Slide a window with a running sum to find the longest or shortest run that meets a rule.
-
Explain why both patterns take
O(n)steps.
-
Lesson 1 — Converging Two Pointers
On a SORTED list, start
loat the front andhiat the back. If the pair sum is too small, moveloup; too big, movehidown; equal, done.values = [1, 4, 6, 9, 11] target = 15 lo = 0 hi = 4 found = False while lo < hi and found == False: total = values[lo] + values[hi] print("check", values[lo], "+", values[hi], "=", total) if total == target: found = True elif total < target: lo = lo + 1 else: hi = hi - 1 print(found)Scroll the code for more ↓
Output
check 1 + 11 = 12 check 4 + 11 = 15 True1 + 11 = 12is too small → moveloup;4 + 11 = 15— found. The pointers CONVERGE; no pair is tested twice.The same sweep can track the CLOSEST sum instead of an exact match.
values = [1, 4, 6, 9] target = 12 lo = 0 hi = 3 best = 999 while lo < hi: total = values[lo] + values[hi] gap = abs(total - target) if gap < best: best = gap if total < target: lo = lo + 1 else: hi = hi - 1 print("closest gap", best)Scroll the code for more ↓
Output
closest gap 1Keep the smallest gap seen while converging; here the closest sum to 12 is off by 1.
Why is it
O(n)? Each pointer only ever moves ONE way, so together they take at mostnsteps — count them.values = [2, 4, 6, 8, 10, 12] target = 100 lo = 0 hi = 5 moves = 0 while lo < hi: total = values[lo] + values[hi] if total < target: lo = lo + 1 else: hi = hi - 1 moves = moves + 1 print("pointer moves:", moves, "for n =", len(values))Scroll the code for more ↓
Output
pointer moves: 5 for n = 6The two pointers make
n - 1 = 5moves total before meeting — linear, not quadratic.Put it together: the program reads
N, atarget, then theNALREADY-SORTED values, and printsYESif two of them sum to the target, elseNO.Try it import sys data = sys.stdin.read() tokens = data.split() n = int(tokens[0]) target = int(tokens[1]) values = [] i = 0 while i < n: values.append(int(tokens[i + 2])) i = i + 1 answer = "NO" lo = 0 hi = n - 1 while lo < hi and answer == "NO": pair_sum = values[lo] + values[hi] if pair_sum == target: answer = "YES" elif pair_sum < target: lo = lo + 1 else: hi = hi - 1 print(answer)Scroll the code for more ↓
Run the full solver from this unit folder:
python assets/l1.py < assets/l1/1.inConverge
lo/hion the sorted list; afound-style flag stops the loop when the pair sum equals the target.Complexity:
O(n)— the input is already sorted, so no sort is needed.Lesson 2 — Sliding Windows
A window
[left, right]grows by addingvalues[right]; keep a RUNNING SUM instead of re-adding. This needs NON-NEGATIVE values so shrinking is safe.values = [5, 2, 1, 1, 3] window_sum = 0 right = 0 while right < len(values): window_sum = window_sum + values[right] print("added", values[right], "-> window sum", window_sum) right = right + 1Scroll the code for more ↓
Output
added 5 -> window sum 5 added 2 -> window sum 7 added 1 -> window sum 8 added 1 -> window sum 9 added 3 -> window sum 12window_sumaccumulates asrightadvances (5, 7, 8, 9, 12) — one add per step, no re-summing.Shrink from the LEFT while the window is over budget; the widest window seen is the longest affordable stretch.
values = [5, 2, 1, 1, 3] limit = 7 left = 0 window_sum = 0 best = 0 right = 0 while right < len(values): window_sum = window_sum + values[right] while window_sum > limit and left <= right: window_sum = window_sum - values[left] left = left + 1 length = right - left + 1 if length > best: best = length right = right + 1 print("longest affordable window:", best)Scroll the code for more ↓
Output
longest affordable window: 4When the sum exceeds 7, drop
values[left]and advanceleft; the widest window within budget here is2 1 1 3(sum 7), length 4.Reverse the goal: shrink while the window MEETS a target to find the SHORTEST qualifying window.
values = [2, 3, 1, 2, 4] target = 6 left = 0 window_sum = 0 shortest = len(values) + 1 right = 0 while right < len(values): window_sum = window_sum + values[right] while window_sum >= target and left <= right: length = right - left + 1 if length < shortest: shortest = length window_sum = window_sum - values[left] left = left + 1 right = right + 1 print("shortest reaching target:", shortest)Scroll the code for more ↓
Output
shortest reaching target: 2Once the sum reaches 6, shrink to record the shortest length; here it is 2 (
2 4).Put it together: the program reads
N, alimit, then theNnon-negative values, and prints the LONGEST window whose sum stays<= limit.Try it import sys data = sys.stdin.read() tokens = data.split() n = int(tokens[0]) limit = int(tokens[1]) values = [] i = 0 while i < n: values.append(int(tokens[i + 2])) i = i + 1 left = 0 right = 0 window_sum = 0 best_length = 0 while right < n: window_sum = window_sum + values[right] while window_sum > limit and left <= right: window_sum = window_sum - values[left] left = left + 1 current_length = right - left + 1 if current_length > best_length: best_length = current_length right = right + 1 print(str(best_length))Scroll the code for more ↓
Run the full solver from this unit folder:
python assets/l2.py < assets/l2/1.inGrow the window with a running sum; while it exceeds
limit, shrink from the left; track the widest width.Complexity:
O(n)—leftandrighteach advance at mostntimes.Two-Pointer Checklist
(1) Converging pointers need a SORTED list; move the end that improves the sum; (2) a sliding window keeps a running sum and needs NON-NEGATIVE values to shrink safely; (3) longest vs shortest just flips the shrink condition; (4) each pointer moves one way →
O(n).-
On a sorted list, move
loup when the sum is too small andhidown when it is too big. -
Each pointer moves only one way, so together they take at most
nsteps. -
A sliding window adds
values[right]as it grows and takes awayvalues[left]as it shrinks, never re-summing. -
Shrink while the window breaks the limit for the LONGEST window, or while it meets the target for the SHORTEST.
-
The sliding window needs non-negative values, so shrinking never raises the sum.
-
You can now replace slow nested-loop scans with linear two-pointer and sliding-window passes.