首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >2026-01-17:完美对的数目。用go语言,给定一个整数数组 nums。我们把满足下面条件的一对索引 (i, j)(且 i < j)称为“完美对”: - 记

2026-01-17:完美对的数目。用go语言,给定一个整数数组 nums。我们把满足下面条件的一对索引 (i, j)(且 i < j)称为“完美对”: - 记

作者头像
福大大架构师每日一题
发布2026-01-22 12:04:45
发布2026-01-22 12:04:45
1710
举报

2026-01-17:完美对的数目。用go语言,给定一个整数数组 nums。我们把满足下面条件的一对索引 (i, j)(且 i < j)称为“完美对”:

  • • 记 a = nums[i],b = nums[j];
  • • 在两者差的绝对值 |a - b| 和和的绝对值 |a + b| 中,较小的那个不大于 a、b 的绝对值中的较小值;
  • • 在两者差的绝对值 |a - b| 和和的绝对值 |a + b| 中,较大的那个不小于 a、b 的绝对值中的较大值。 任务是统计数组中不同的这样的“完美对”的数量。说明:|x| 表示 x 的绝对值(非负数)。 2 <= nums.length <= 100000。 -1000000000 <= nums[i] <= 1000000000。 输入: nums = [-3,2,-1,4]。 输出: 4。 解释: 有 4 个完美对:

(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。

🧠 算法步骤分解

整个算法的核心思路是,在将数组中的负数转换为正数并排序后,利用双指针技巧高效地统计满足特定数值条件的数对。

  1. 1. 处理负数
    • 操作:遍历整数数组 nums,如果某个元素 x 是负数,则将其替换为其绝对值(即 x *= -1)。
    • 目的:由于题目条件涉及绝对值,且完美对的条件对于 (a, b)(-a, -b) 等情形是等价的,将所有数转为非负数可以简化后续的比较和计算,避免符号带来的复杂性。这一步确保了数组中所有元素都是非负的。
  2. 2. 数组排序
    • 操作:使用排序算法(代码中为 slices.Sort(nums))对处理后的非负数组进行升序排序。
    • 目的:排序是为了让数值相近的元素聚集在一起,为后续使用双指针法创造条件。在一个有序的数组中,可以更高效地找到满足特定大小关系的数对。
  3. 3. 双指针统计完美对
    • 操作:初始化一个指针left指向数组起始位置(0)。然后遍历数组,将当前遍历到的元素nums[j]视为数对中的b。在遍历过程中,调整left指针的位置,使得从leftj-1的所有元素nums[i]都满足nums[i] * 2 >= b(或者说,跳过那些nums[i] * 2 < b的元素)。对于每个j,满足条件的i的范围就是leftj-1,因此完美对的数量增加(j - left)
    • 关键点:在排序后的非负数组中,完美对的条件可以简化为判断ab的大小关系。这里的逻辑是,对于固定的b,需要找到所有满足条件的aa <= b),使得ab的数值关系符合原始题目中关于绝对值和与差的条件。通过检查a * 2b的关系,可以高效地筛选这些数对。指针left随着j 的增大而单向向右移动,不会回退,这保证了高效性。

⏱️ 复杂度分析

  • 总的时间复杂度O(n log n)。 这主要由排序步骤决定,因为排序的时间复杂度通常是 O(n log n)。后续的双指针遍历过程,left 指针和 j 指针各遍历数组一次,是线性的 O(n) 操作。因此,整个算法的总时间复杂度由排序步骤主导,为 O(n log n)。
  • 总的额外空间复杂度O(1)。 算法在执行过程中只使用了固定数量的额外变量(如 ans, left, j 等),这些空间不随输入数组的大小 n 而变化。排序操作如果是在原数组上进行(如代码中的 slices.Sort),通常也不需要额外的空间(即原地排序)。因此,额外的空间复杂度是常数级别的 O(1)。

Go完整代码如下:

.

代码语言:javascript
复制
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)
}

Python完整代码如下:

代码语言:javascript
复制
# -*-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()

C++完整代码如下:

代码语言:javascript
复制
#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科普文章、工具评测、提升效率的秘籍以及行业洞察。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-01-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 福大大架构师每日一题 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 🧠 算法步骤分解
  • ⏱️ 复杂度分析
  • Go完整代码如下:
  • Python完整代码如下:
  • C++完整代码如下:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档