Problem overview
The method CountPairs(int n, int sum) counts the pairs of integers (x, y) with 1 <= x, y <= n and x + y == sum. Pairs that differ only in order count once, so (1, 5) and (5, 1) are the same pair.
For n = 7 and sum = 6, the valid pairs are (1, 5), (2, 4) and (3, 3), so the answer is 3. A pair may use the same number twice, which is why (3, 3) counts.
Approach
The lesson asks for O(n^2) time and O(1) extra space. That is a brute-force budget: try every candidate pair and test each one. No cleverness is needed, and the lesson's point is writing the two loops correctly.
To count each unordered pair once, always put the smaller number first. Let i run from 1 to n, and let j run from i to n. Then every pair appears exactly once with i <= j, and (5, 1) is never visited because j would have to start below i.
The loops try the pairs in this order for n = 7: (1, 1), (1, 2), ... (1, 7), then (2, 2) through (2, 7), and so on. The matches for sum = 6 are (1, 5), (2, 4) and (3, 3).
Tracing the example
With n = 7 and sum = 6, the check i + j == sum succeeds only when j equals 6 - i. Here is what each pass of the outer loop does:
i | Values of j tried | Matching j | result afterwards |
|---|---|---|---|
| 1 | 1 to 7 | 5 | 1 |
| 2 | 2 to 7 | 4 | 2 |
| 3 | 3 to 7 | 3 | 3 |
| 4 | 4 to 7 | none, because 2 is below 4 | 3 |
| 5 | 5 to 7 | none | 3 |
| 6 | 6 to 7 | none | 3 |
| 7 | 7 to 7 | none | 3 |
From i = 4 on, the partner 6 - i is smaller than i. That pair was already counted earlier, with the numbers the other way round, and the inner loop never goes back to look at it. This is exactly how starting j at i avoids double counting.
Step by step
- Declare
result. Anintstarting at 0 holds the count so far. - Loop over the first number.
istarts at 1 and runs whilei <= n. The bound is inclusive becausenitself is allowed. - Loop over the second number. Inside it,
jstarts ati, not at 1, and runs whilej <= n. Starting atikeeps every pair in order and allowsi == j. - Test and count. If
i + j == sum, incrementresult. Each match is a different pair, so each adds exactly 1. - Return
resultafter both loops finish.
The solution in C#
class Solution {
public int CountPairs(int n, int sum) {
int result = 0;
for (int i = 1; i <= n; i++) {
for (int j = i; j <= n; j++) {
if (i + j == sum) {
result++;
}
}
}
return result;
}
}
Two details are worth a look. The loops use <= because the range 1 to n includes both ends, unlike the < array.Length bound you use for array indices. And result++ is shorthand for result = result + 1.
C# details
- Every variable is declared with its type.
int result = 0;must be initialised before it is used. C# refuses to compile code that reads a local variable that may never have been assigned. - The loop variables are scoped to their loops.
iexists only inside the outer loop andjonly inside the inner one, and each new pass of the outer loop creates a freshjthat starts again ati. - Integer addition wraps silently. If
i + jexceeded theintrange, C# would not report an error by default; the result would wrap around to a negative number. It isn't a concern here, because a loop overn^2pairs is only practical for modestn, wherei + jis far from the limit.
Another way to look at it
You could count ordered pairs with two full loops from 1 to n, then fix the total: every pair with x != y was counted twice and every pair with x == y once. That needs extra bookkeeping. Starting the inner loop at i gives the right count directly.
Complexity
Time: O(n^2). For i = 1 the inner loop runs n times, for i = 2 it runs n - 1 times, and so on down to 1. The total is n + (n - 1) + ... + 1 = n(n + 1) / 2, which grows like n^2.
Space: O(1). The method uses only result, i and j, whatever the size of n.
The inner loop does a lot of pointless work: for each i, only one value of j can possibly match, namely sum - i. A faster version would check directly whether that value lies between i and n, which makes the whole method O(n). This lesson practises the nested-loop pattern, so it keeps the full search.
Edge cases and common mistakes
- Starting
jat 1. This counts(1, 5)and(5, 1)separately, so the example would give 5 instead of 3. - Starting
jati + 1. This drops pairs with two equal numbers, such as(3, 3). The example would give 2. - Using
<instead of<=. The loops would never trynitself.CountPairs(4, 8)must return 1, from(4, 4). - A sum that is too large or too small. If
sumis bigger than2 * n, no pair works and the answer is 0.CountPairs(3, 10)returns 0. - The smallest sum.
CountPairs(5, 2)returns 1, from(1, 1).
Testing
n = 7,sum = 6gives 3.n = 4,sum = 8gives 1: only(4, 4)works, and it checks the inclusive bound and the equal-numbers case at once.n = 3,sum = 10gives 0, because the largest possible sum is 6.n = 5,sum = 2gives 1, from(1, 1), the smallest possible pair.n = 1,sum = 2gives 1: the loops run once, and(1, 1)matches.