You are given a function f(x, y) where x and y are positive integers. The function is strictly increasing with respect to both variables: that is, f(x, y) < f(x + 1, y) and f(x, y) < f(x, y + 1) for all positive integers x and y.
Given a target value z, your task is to find all positive integer pairs (x, y) such that f(x, y) == z. The function f is provided as an interface or black box (you can only call it, not examine its code).
Constraints:
(x, y) such that both x and y are positive integers.
At first glance, the problem could be solved using a brute-force approach: try every possible pair (x, y) in the allowed range and check if f(x, y) == z. However, since f is strictly increasing with respect to both variables, we can use this property to optimize our search.
The strictly increasing nature means:
f(x, y) < z, you need to increase x or y to get closer to z.f(x, y) > z, you need to decrease x or y to get closer to z.Here’s how to efficiently find all solutions:
x = 1 and y = max_y (e.g., 1000). This positions us at the top-left or bottom-left of the search grid.
x is within range and y is within range:
f(x, y).f(x, y) == z, record (x, y) as a solution, then increment x (since increasing y will only make f(x, y) larger).
f(x, y) < z, increment x to increase the value.
f(x, y) > z, decrement y to decrease the value.
x or y go out of bounds.
This approach ensures that each pair is checked at most once, and the search space is pruned efficiently using the strictly increasing property.
Suppose f(x, y) = x * y and z = 5. We want all positive integer pairs (x, y) such that x * y = 5.
x = 1, y = 1000 (or the max allowed value).f(1, 1000) = 1000 (too big), so decrement y to 999, 998, ..., until y = 5.f(1, 5) = 5, record (1, 5).x to 2, check f(2, 5) = 10 (too big), so decrement y to 4, 3, etc. No solution.x = 5, y = 1 where f(5, 1) = 5. Record (5, 1).z.
The pairs found are (1, 5) and (5, 1).
Brute-force approach: Tries all possible (x, y) pairs in the range, leading to O(N2) time complexity (where N is the upper bound, e.g., 1000).
Optimized approach: Since each step either increments x or decrements y, the maximum number of steps is O(N) + O(N) = O(N). Thus, the optimized solution is linear in the size of the range.
Space complexity: Only the output list of solutions is stored, so space is O(K), where K is the number of valid pairs.
By leveraging the strictly increasing property of the function f(x, y), we avoid brute-force search and instead use a two-pointer-like approach. This enables us to efficiently scan the grid of possible solutions, ensuring each pair is considered only once. The key insight is to adjust x and y based on whether the current value is less than or greater than the target, similar to searching in a sorted matrix. This makes the solution both elegant and highly efficient.
# Suppose f is provided as follows:
# For testing, let's use f(x, y) = x * y
def f(x, y):
return x * y
def findSolution(customfunction, z):
res = []
x, y = 1, 1000
while x <= 1000 and y >= 1:
val = customfunction(x, y)
if val == z:
res.append([x, y])
x += 1
elif val < z:
x += 1
else:
y -= 1
return res
/*
Suppose CustomFunction is a class with int f(int x, int y);
For testing, f(x, y) = x * y
*/
class Solution {
public:
vector<vector<int>> findSolution(CustomFunction& customfunction, int z) {
vector<vector<int>> res;
int x = 1, y = 1000;
while (x <= 1000 && y >= 1) {
int val = customfunction.f(x, y);
if (val == z) {
res.push_back({x, y});
x++;
} else if (val < z) {
x++;
} else {
y--;
}
}
return res;
}
};
/*
Suppose CustomFunction has int f(int x, int y);
For testing, f(x, y) = x * y
*/
class Solution {
public List<List<Integer>> findSolution(CustomFunction customfunction, int z) {
List<List<Integer>> res = new ArrayList<>();
int x = 1, y = 1000;
while (x <= 1000 && y >= 1) {
int val = customfunction.f(x, y);
if (val == z) {
res.add(Arrays.asList(x, y));
x++;
} else if (val < z) {
x++;
} else {
y--;
}
}
return res;
}
}
/*
Suppose customfunction.f(x, y) is provided.
For testing, f(x, y) = x * y
*/
var findSolution = function(customfunction, z) {
const res = [];
let x = 1, y = 1000;
while (x <= 1000 && y >= 1) {
const val = customfunction.f(x, y);
if (val === z) {
res.push([x, y]);
x++;
} else if (val < z) {
x++;
} else {
y--;
}
}
return res;
};