ExampleDifficulty: Intermediate3 min

Two Pointers Example: Triples of Weights That Make a Target

Fix one value, run the pair search on the rest, and skip any value equal to the one before so no triple is counted twice.

Finding every distinct triple that adds up to a target takes a sorted array, one fixed index and an opposite-ends pair search on the values after it. A gym has plates of 2, 2, 3, 3, 4, 5 and 6 kilograms, and the question is every distinct set of three plates weighing 10 kilograms in all, where two sets that use the same weights count once.

How many distinct triples weigh 10 kilograms?

Three: 2 2 6, 2 3 5 and 3 3 4. A search that does not skip repeated values reports four, because the second 2 finds 2 3 5 again.

Sort the plates, then fix each index i in turn and search the values after it for a pair adding up to 10 − values[i] with two pointers. Each fixed index costs one O(n) pass, so the whole search is O(n²) time for n plates, against O(n³) for checking every triple.

Repeated weights are skipped in three places. A fixed value equal to the one before it is skipped, since every triple it could start was already found. After a triple is found, the left pointer moves past values equal to the one it used, and the right pointer past values equal to its own, so the same pair is not reported again for this fixed value. Sorting is what makes all three work, because it puts equal values next to each other.

On the sorted plates 2 2 3 3 4 5 6, each fixed value either finds its pairs or is skipped as a repeat.

Fixing each plate of 2 2 3 3 4 5 6 for a total of 10
Fixed valuePairs foundSkipped as duplicate
2, index 02 + 6, 3 + 5No
2, index 1none searchedYes
3, index 23 + 4No
3, index 3none searchedYes
4, index 4noneNo

The listing runs the search with and without the skips, on the same plates.

weight_triples.pypy
def triples(weights: list[int], target: int, skip_repeats: bool) -> list[tuple[int, int, int]]:
    values = sorted(weights)
    found = []
    for i in range(len(values) - 2):
        if skip_repeats and i > 0 and values[i] == values[i - 1]:
            continue
        left, right = i + 1, len(values) - 1
        while left < right:
            total = values[i] + values[left] + values[right]
            if total == target:
                found.append((values[i], values[left], values[right]))
                left += 1
                right -= 1
                while skip_repeats and left < right and values[left] == values[left - 1]:
                    left += 1
                while skip_repeats and left < right and values[right] == values[right + 1]:
                    right -= 1
            elif total < target:
                left += 1
            else:
                right -= 1
    return found


weights = [2, 2, 3, 3, 4, 5, 6]
print("with the skips:", triples(weights, 10, True))
print("without them:  ", triples(weights, 10, False))
OutputRan with python:3.14.8-slim-trixie (Python 3.14.8)
with the skips: [(2, 2, 6), (2, 3, 5), (3, 3, 4)]
without them:   [(2, 2, 6), (2, 3, 5), (2, 3, 5), (3, 3, 4)]

Without the skips, the second 2 repeats the first one's search and reports 2 3 5 a second time. With them, each set of weights appears once. The cost stays O(n²) time either way, plus O(n log n) for the sort, and the search needs O(1) extra space beyond the list of answers. Fixing one value and searching the rest extends to four values with a second fixed index, at O(n³).