
2026-01-17:完美对的数目。用go语言,给定一个整数数组 nums。我们把满足下面条件的一对索引 (i, j)(且 i < j)称为“完美对”:
(i, j) | (a, b) | min(|a - b|, |a + b|) | min(|a|, |b|) | max(|a - b|, |a + b|) | max(|a|, |b|) |
|---|---|---|---|---|---|
(0, 1) | (-3, 2) | min(|-3 - 2|, |-3 + 2|) = min(5, 1) = 1 | min(|-3|, |2|) = min(3, 2) = 2 | max(|-3 - 2|, |-3 + 2|) = max(5, 1) = 5 | max(|-3|, |2|) = max(3, 2) = 3 |
(0, 3) | (-3, 4) | min(|-3 - 4|, |-3 + 4|) = min(7, 1) = 1 | min(|-3|, |4|) = min(3, 4) = 3 | max(|-3 - 4|, |-3 + 4|) = max(7, 1) = 7 | max(|-3|, |4|) = max(3, 4) = 4 |
(1, 2) | (2, -1) | min(|2 - (-1)|, |2 + (-1)|) = min(3, 1) = 1 | min(|2|, |-1|) = min(2, 1) = 1 | max(|2 - (-1)|, |2 + (-1)|) = max(3, 1) = 3 | max(|2|, |-1|) = max(2, 1) = 2 |
(1, 3) | (2, 4) | min(|2 - 4|, |2 + 4|) = min(2, 6) = 2 | min(|2|, |4|) = min(2, 4) = 2 | max(|2 - 4|, |2 + 4|) = max(2, 6) = 6 | max(|2|, |4|) = max(2, 4) = 4 |
题目来自力扣3649。
整个算法的核心思路是,在将数组中的负数转换为正数并排序后,利用双指针技巧高效地统计满足特定数值条件的数对。
nums,如果某个元素 x 是负数,则将其替换为其绝对值(即 x *= -1)。(a, b) 和 (-a, -b) 等情形是等价的,将所有数转为非负数可以简化后续的比较和计算,避免符号带来的复杂性。这一步确保了数组中所有元素都是非负的。slices.Sort(nums))对处理后的非负数组进行升序排序。left指向数组起始位置(0)。然后遍历数组,将当前遍历到的元素nums[j]视为数对中的b。在遍历过程中,调整left指针的位置,使得从left到j-1的所有元素nums[i]都满足nums[i] * 2 >= b(或者说,跳过那些nums[i] * 2 < b的元素)。对于每个j,满足条件的i的范围就是left到j-1,因此完美对的数量增加(j - left)。a和b的大小关系。这里的逻辑是,对于固定的b,需要找到所有满足条件的a(a <= b),使得a和b的数值关系符合原始题目中关于绝对值和与差的条件。通过检查a * 2与b的关系,可以高效地筛选这些数对。指针left随着j 的增大而单向向右移动,不会回退,这保证了高效性。left 指针和 j 指针各遍历数组一次,是线性的 O(n) 操作。因此,整个算法的总时间复杂度由排序步骤主导,为 O(n log n)。ans, left, j 等),这些空间不随输入数组的大小 n 而变化。排序操作如果是在原数组上进行(如代码中的 slices.Sort),通常也不需要额外的空间(即原地排序)。因此,额外的空间复杂度是常数级别的 O(1)。.
package main
import (
"fmt"
"slices"
)
func perfectPairs(nums []int) (ans int64) {
for i, x := range nums {
if x < 0 {
nums[i] *= -1
}
}
slices.Sort(nums)
left := 0
for j, b := range nums {
for nums[left]*2 < b {
left++
}
// a=nums[i],其中 i 最小是 left,最大是 j-1,一共有 j-left 个
ans += int64(j - left)
}
return
}
func main() {
nums := []int{-3, 2, -1, 4}
result := perfectPairs(nums)
fmt.Println(result)
}

# -*-coding:utf-8-*-
from typing import List
def perfectPairs(nums: List[int]) -> int:
# 将所有数字转为非负
nums = [abs(x) for x in nums]
# 排序
nums.sort()
ans = 0
left = 0
for j, b in enumerate(nums):
# 移动左指针,找到满足 a*2 >= b 的最小索引
while left < j and nums[left] * 2 < b:
left += 1
# a = nums[i],其中 i 从 left 到 j-1,共 j-left 个
ans += j - left
return ans
def main():
nums = [-3, 2, -1, 4]
result = perfectPairs(nums)
print(result)
if __name__ == "__main__":
main()
#include <vector>
#include <algorithm>
#include <cstdlib> // for abs
#include <iostream>
long long perfectPairs(std::vector<int>& nums) {
// 将所有数字转为非负
for (int& num : nums) {
if (num < 0) {
num = -num;
}
}
// 排序
std::sort(nums.begin(), nums.end());
long long ans = 0;
int left = 0;
int n = nums.size();
for (int j = 0; j < n; ++j) {
int b = nums[j];
// 移动左指针,找到满足 a*2 >= b 的最小索引
while (left < j && nums[left] * 2 < b) {
++left;
}
// a = nums[i],其中 i 从 left 到 j-1,共 j-left 个
ans += j - left;
}
return ans;
}
int main() {
std::vector<int> nums = {-3, 2, -1, 4};
long long result = perfectPairs(nums);
std::cout << result << std::endl;
return0;
}

我们相信人工智能为普通人提供了一种“增强工具”,并致力于分享全方位的AI知识。在这里,您可以找到最新的AI科普文章、工具评测、提升效率的秘籍以及行业洞察。