Python 1237.py
class Solution:
def findSolution(self, customfunction: 'CustomFunction', z: int) -> List[List[int]]:
# [ 1,2,...,1000 ]
low = 1
high = 1000
all = list(range(low, high + 1))
for x in all:
# no solution for x ? (these checks aren't needed, they just improve performance)
if customfunction.f(x, low) > z:
break
if customfunction.f(x, high) < z:
continue
# find lowest y where f(x, y) == z
left = bisect_left(all, z, key = lambda y, x=x : customfunction.f(x, y))
# find lowest y where f(x, y) > z
right = bisect_left(all, z + 1, key = lambda y, x=x : customfunction.f(x, y))
# linear scan until f(x, y) becomes too large
for y in range(all[left], all[right]):
yield [ x, y ]
Difficulty
and has an acceptance rate of about 70% (100k+ submissions).
Typical patterns to solve this problem:
- Binary Search
- Interactive
- Math
- Two Pointers
AI Disclaimer
However, two years later I set up this website and used various AI tools to generate most of the walkthrough / explanations below.
See this dedicated page for more details.
Code Walkthrough
Overview
The provided implementation searches for all integer pairs ((x, y)) within the inclusive range ([1, 1000]) that satisfy the equation customfunction.f(x, y) == z. The method returns a generator that yields each qualifying pair as a two-element list. The algorithm combines a linear scan over the possible values of x with binary search techniques to efficiently locate the corresponding y values for each x.
Key Steps
The first step creates the complete search domain for both variables.
low = 1
high = 1000
all = list(range(low, high + 1))
A loop iterates over every candidate x in the domain.
for x in all:
Inside the loop two quick checks are performed to eliminate x values that cannot possibly produce a solution. The first check stops the loop entirely when the smallest possible y already yields a value larger than z.
if customfunction.f(x, low) > z:
break
The second check skips the current x when even the largest possible y is still smaller than z.
if customfunction.f(x, high) < z:
continue
When an x passes the preliminary filters, two binary searches determine the interval of y values that could satisfy the equation. The left bound finds the smallest y for which the function value is at least z.
left = bisect_left(all, z, key=lambda y, x=x: customfunction.f(x, y))
The right bound finds the smallest y for which the function value exceeds z.
right = bisect_left(all, z + 1, key=lambda y, x=x: customfunction.f(x, y))
With the interval [left, right) identified, a simple linear scan enumerates each y that yields exactly z.
for y in range(all[left], all[right]):
yield [x, y]
The use of yield makes the method a generator, allowing callers to consume results lazily without allocating a full list of pairs.
Edge Cases Handled
When the function value at the minimum y already exceeds z, the outer loop terminates early because no larger x can produce a smaller result, given the monotonic nature implied by the checks. Conversely, if the function value at the maximum y is still below z, the current x is skipped because no y in the domain can satisfy the target. The binary searches gracefully handle situations where no y meets the condition: if the left and right indices are equal, the subsequent for loop iterates over an empty range, producing no output for that x. This behavior correctly represents the absence of solutions without raising errors.
Performance Optimizations
The early break condition eliminates entire suffixes of the x domain once the function value surpasses z at the lowest y. The continue condition skips entire prefixes of the y domain for a given x when the function value cannot reach z. By employing bisect_left with a custom key, the algorithm narrows the candidate y interval to the smallest possible range, reducing the number of function evaluations needed for each x. The final linear scan only processes the narrowed interval, avoiding unnecessary checks outside the feasible region. Additionally, the generator pattern prevents the accumulation of all result pairs in memory, delivering each pair on demand and keeping the runtime footprint low.
ELI5 - Simplified Explanation
Imagine there is a secret treasure box that only opens when two hidden numbers add up to a special goal number. This computer program acts like a detective trying to solve these math puzzles.
First, the detective creates a list of numbers from one to one thousand to test as possible choices. It walks through each number one by one to see if it can be the first half of the secret pair. If a number is already too big to possibly work, the detective stops searching because it knows the answer cannot be found there.
For every number that looks like a good guess, the detective uses a clever trick to search through the second set of numbers very quickly. Think of this like looking through a library of pages; instead of turning every single page to find the story, the detective jumps to the middle of the book to decide which direction to look.
Once the detective finds the right spot, it carefully checks all the numbers that match the goal. When everything clicks and the two numbers combine to equal the secret target, the detective puts that pair of numbers aside to show you that it found a match. This continues until the detective has looked at every possible combination.
Code Quality
Complexity Analysis
Other Solutions
Obviously, I did that after I solved the problem myself.
In general, AlgoMonster and WalkCCC solutions are high-quality and always worth a look.
I haven't checked most of the other solutions, but they might be helpful as well.
And of course, the LeetCode forum is always a good place (or even the best) to look for alternative approaches.
(click on a column header to sort the table)
| author | |||||||||
|---|---|---|---|---|---|---|---|---|---|
| author | solutions | ||||||||
| www | AlgoMonster | C++ | Python | Java | TS | ||||
| WalkCCC | C++ | Python | Java | ||||||
| leetcode.ca | C++ | Python | Java | Go | TS | ||||
| MemoryLimitExceeded | C++ | Python | |||||||
| Progiez | C++ | Python | Java | ||||||
| github | BigEggStudy | C# | |||||||
| black-shadows | C++ | ||||||||
| charles-wangkai | Java | ||||||||
| DimitrisJim | C | ||||||||
| fsq | C++ | ||||||||
| JoshCrozier | JS | ||||||||
| keineahnung2345 | C++ | ||||||||
| lkwq007 | Python | ||||||||
| suxrobGM | C# | ||||||||
| varunu28 | Java | ||||||||
| wisdompeak | C++ | ||||||||
| YuriSpiridonov | Python | ||||||||
| AlgoMonster | C++, Python, Java, TypeScript | ||||||||
| WalkCCC | C++, Python, Java | ||||||||
| leetcode.ca | C++, Go, Java, Python, TypeScript | ||||||||
| MemoryLimitExceeded | Python, C++ | ||||||||
| Progiez | C++, Java, Python | ||||||||
| BigEggStudy | C# | ||||||||
| black-shadows | C++, C++ | ||||||||
| charles-wangkai | Java | ||||||||
| DimitrisJim | C | ||||||||
| fsq | C++ | ||||||||
| JoshCrozier | JavaScript | ||||||||
| keineahnung2345 | C++ | ||||||||
| lkwq007 | Python | ||||||||
| suxrobGM | C# | ||||||||
| varunu28 | Java | ||||||||
| wisdompeak | C++ | ||||||||
| YuriSpiridonov | Python |
Videos
Solved On The Same Day
- problem 2529: Maximum Count of Positive Integer and Negative Integer
- problem 532: K-diff Pairs in an Array
- problem 718: Maximum Length of Repeated Subarray
- problem 826: Most Profit Assigning Work
- problem 1283: Find the Smallest Divisor Given a Threshold
- problem 1552: Magnetic Force Between Two Balls
- problem 1561: Maximum Number of Coins You Can Get
- problem 1760: Minimum Limit of Balls in a Bag
- problem 1870: Minimum Speed to Arrive on Time
Extra
- Tech Stack - my development environment and tools
- AI - how AI helped me create this website (NOT solving the problems)
- Progress - progression over time
- Quality - code quality