本文涉及的基础知识点
C++算法:滑动窗口及双指针总结
LeetCode2563. 统计公平数对的数目
给你一个下标从 0 开始、长度为 n 的整数数组 nums ,和两个整数 lower 和 upper ,返回 公平数对的数目 。
如果 (i, j) 数对满足以下情况,则认为它是一个 公平数对 :
0 <= i < j < n,且
lower <= nums[i] + nums[j] <= upper
示例 1:
输入:nums = [0,1,7,4,4,5], lower = 3, upper = 6
输出:6
解释:共计 6 个公平数对:(0,3)、(0,4)、(0,5)、(1,3)、(1,4) 和 (1,5) 。
示例 2:
输入:nums = [1,7,9,2,5], lower = 11, upper = 11
输出:1
解释:只有单个公平数对:(2,3) 。
提示:
1 <= nums.length <= 105
nums.length == n
-109 <= nums[i] <= 109
-109 <= lower <= upper <= 109
C++滑动窗口
对nums排序。
枚举i,符合条件一 nums[i]+nums[j] >=lower,条件二 nums[i]+nums[j] > upper的(i,j)是公平数对。符合条件一的最小解是j1,符合条件二最小解是j2,则(i,j)都是公平点对,j ∈ \in ∈[j1,j2)。
三指针为:i,j3,j4。j3 = j1-1,j4=j2-1。
显然i增加,j3,j4减少。
i = 0 To n-1
while ((j3 > i) && (nums[j3] + nums[i] >= lower)) j3–;
while ((j4 > i) && (nums[j4] + nums[i] > upper)) j4–;
和i能组成的合法点对:(j4-j3)
(i,j)符合条件一,则(i+1,j)也符合条件一。故j+1及更大的数,一定不是最小接。 → \rightarrow → i++后,j不复位。 → \rightarrow → 时间复杂度O(n)。
注意:由于i++,所以可能i3<i4。故:ret += max(i,j4) - max(i,j3);
代码
核心代码第一版
class Solution {
public:
long long countFairPairs(vector<int>& nums, int lower, int upper) {
const int N = nums.size();
sort(nums.begin(), nums.end());
long long ret = 0;
for (int i = 0, j3 = N - 1, j4 = N - 1; i < N; i++) {
while ((j3 > i) && (nums[j3] + nums[i] >= lower)) j3--;
while ((j4 > i) && (nums[j4] + nums[i] > upper)) j4--;
ret += max(i,j4) - max(i,j3);
}
return ret;
}
};
单元测试
vector<int> nums;
int lower, upper;
TEST_METHOD(TestMethod1)
{
nums = { 3,4 }, lower = 6, upper = 6;
auto res = Solution().countFairPairs(nums, lower, upper);
AssertEx(0LL, res);
}
TEST_METHOD(TestMethod2)
{
nums = { 3,4 }, lower = 6, upper = 7;
auto res = Solution().countFairPairs(nums, lower, upper);
AssertEx(1LL, res);
}
TEST_METHOD(TestMethod11)
{
nums = { 0, 1, 7, 4, 4, 5 }, lower = 3, upper = 6;
auto res = Solution().countFairPairs(nums, lower, upper);
AssertEx(6LL, res);
}
TEST_METHOD(TestMethod12)
{
nums = { 1,7,9,2,5 }, lower = 11, upper = 11;
auto res = Solution().countFairPairs(nums, lower, upper);
AssertEx(1LL, res);
}