Two pointers replace a loop inside a loop with two indexes that each move in one direction. On a sorted list, start one at each end. If the pair adds up to too little, no pair with the left value can work, because the right value is the largest one still in play, so move the left pointer right. If it adds up to too much, move the right pointer left. Every step rules out one value for good, which is why you never skip an answer.
The same idea merges two sorted lists (a pointer in each, take the smaller value), checks a code from both ends at once, and compacts a list in place with a read pointer and a write pointer.
Each pointer crosses the list once: O(n) time and O(1) extra space. Decide when the loop stops: when the pointers meet, or one item pairs with itself. The method needs sorted input, so sort first or use a hash map. Test an empty list, one item, repeated values and negative numbers.
weights = [2, 3, 5, 8, 11, 14], target = 11
left 0 (2), right 5 (14): 16 > 11, move right in
left 0 (2), right 4 (11): 13 > 11, move right in
left 0 (2), right 3 (8): 10 < 11, move left in
left 1 (3), right 3 (8): 11 = 11, found
answer: [1, 3], after 4 sums instead of 15 pairs
A sum that is too big can only shrink by dropping the heaviest weight; one that is too small can only grow by dropping the lightest.