一键导入
algo-two-pointers
Two-pointer scans — opposite ends, same direction, fast/slow — for sorted arrays, partitioning, cycle detection.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Two-pointer scans — opposite ends, same direction, fast/slow — for sorted arrays, partitioning, cycle detection.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | algo-two-pointers |
| description | Two-pointer scans — opposite ends, same direction, fast/slow — for sorted arrays, partitioning, cycle detection. |
| when-to-use | Sorted-array pair sums, palindromes, removing duplicates in place, linked-list cycle detection, partitioning. |
Two-pointer scans turn many O(n^2) loops into O(n). There are
three common shapes:
lo at the start, hi at the end, walk
inward (sorted-array pair sum, palindrome).j advances every step,
i advances conditionally (in-place dedup, partition).slow advances by 1 step, fast by 2 (linked-
list cycle detection, middle of list).O(n) amortisation.arr[lo] + arr[hi] is
too small, only lo++ can help (any pair with the current lo
paired against a smaller hi is even smaller).O(n) for a single linear scan; O(n^2) for k-sum
variants where one pointer is fixed and a two-pointer scan is
done inside.O(1) extra.def pair_sum_sorted(arr: list[int], target: int) -> tuple[int, int] | None:
"""Indices of two values in sorted ``arr`` summing to target."""
lo, hi = 0, len(arr) - 1
while lo < hi:
s = arr[lo] + arr[hi]
if s == target: return (lo, hi)
if s < target: lo += 1
else: hi -= 1
return None
Note: requires sorted input. If the input is unsorted, hashing is typically simpler; only use two-pointers when sorting is already done or stable indices don't matter.
def dedup_sorted(arr: list[int]) -> int:
"""Compact sorted ``arr`` so the first ``k`` entries are unique. Returns k."""
if not arr: return 0
i = 0 # write index
for j in range(1, len(arr)):
if arr[j] != arr[i]:
i += 1
arr[i] = arr[j]
return i + 1
The "write pointer + read pointer" form is the basis for all in-place partitioning algorithms (Lomuto, Hoare).
function hasCycle(head) {
let slow = head, fast = head;
while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
if (slow === fast) return true;
}
return false;
}
If the lists meet, there is a cycle. The mathematical proof: in a
cycle of length L, fast gains 1 step on slow per iteration, so
they meet within L iterations of slow entering the cycle.
hi = len(arr) vs hi = len(arr) - 1. Choose
one convention; the templates above use inclusive hi. Mixing
conventions causes index-out-of-range or missed pairs.head == null. Guard the loop
with fast && fast.next.lo == 0, hi == n - 1 matches).head.next = head).The dedup template generalises to any "compact while preserving order under predicate P" — change the comparator and you get remove-zeroes, remove-duplicates-keep-at-most-twice, etc.
Breadth-first search — shortest path on unweighted graphs, level-order traversal, and the `visited` discipline that prevents O(2^n) blowups.
Binary search invariants, half-open intervals, and the `lo<hi` template that beats off-by-one bugs.
Depth-first search — recursive vs iterative, recursion-depth gotchas, three-color cycle detection, topological sort.
Dynamic programming — state design, memoization vs tabulation, dimension-reduction, and when DP is the wrong tool.
Pick the right traversal — BFS for unweighted shortest path, Dijkstra for weighted, A* for goal-directed, 0/1-BFS for binary weights.
Greedy algorithms — exchange-argument proofs, when greedy beats DP, classic patterns (interval scheduling, Huffman, scheduling).