统计坏数对的数目

·  阅读 17

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第18天,点击查看活动详情

说在前面

🎈不知道大家对于算法的学习是一个怎样的心态呢?为了面试还是因为兴趣?不管是处于什么原因,算法学习需要持续保持,今天让我们一起来看看这一道题目————统计坏数对的数目

题目描述

给你一个下标从 0 开始的整数数组 nums 。如果 i < j 且 j - i != nums[j] - nums[i] ,那么我们称 (i, j) 是一个 坏数对 。

请你返回 nums 中 坏数对 的总数目。

示例 1:

输入:nums = [4,1,3,3]
输出:5
解释:数对 (0, 1) 是坏数对,因为 1 - 0 != 1 - 4 
数对 (0, 2) 是坏数对,因为 2 - 0 != 3 - 4, 2 != -1 
数对 (0, 3) 是坏数对,因为 3 - 0 != 3 - 4, 3 != -1 
数对 (1, 2) 是坏数对,因为 2 - 1 != 3 - 1, 1 != 2 
数对 (2, 3) 是坏数对,因为 3 - 2 != 3 - 3, 1 != 0 
总共有 5 个坏数对,所以我们返回 5 
复制代码

示例 2:

输入:nums = [1,2,3,4,5]
输出:0
解释:没有坏数对。
复制代码

提示:

  • 1 <= nums.length <= 10^5
  • 1 <= nums[i] <= 10^9

思路分析

首先我们还是要先来理解一下题意,题目对于坏数对的定义是这样的:i < j 且 j - i != nums[j] - nums[i],也就是数组中的两个数之差与下标之差不相等即为坏数对。

那么是不是直接两层循环遍历一下就可以了?让我们先来看看题目的数据范围:

  • 1 <= nums.length <= 10^5
  • 1 <= nums[i] <= 10^9

很明显,两重循环遍历的话时间复杂度为O(n^2),这样肯定会超时,所以我们应该换一种更好地方式来统计坏数对的数目。

image.png

首先我们先来找一下有没有什么规律,如上图,我们可以将数组的值a[i]分解成下标 + xn的形式,这个时候我们会发现,a[j] - a[i] = xi - xj + j - i,再看一下坏素组的定义:i < j 且 j - i != nums[j] - nums[i],也就是说:j - i != xi - xj + j - i,所以只要xi - xj != 0,则可以说明为坏数对,那么我们可以这样来解答这道题目:

  • 1、统计数组值与下标之差 x
let flag = {};
for(let i = 0; i < nums.length; i++){
    flag[nums[i] - i] = (flag[nums[i] - i] || 0) + 1;
}
复制代码
  • 2、统计x不同值得组合数
let res = 0;
let len = nums.length;
for(let key in flag){
    res += (len - flag[key]) * flag[key];
}
return res / 2;
复制代码

AC代码

/**
 * @param {number[]} nums
 * @return {number}
 */
 var countBadPairs = function(nums) {
    let flag = {};
    for(let i = 0; i < nums.length; i++){
        flag[nums[i] - i] = (flag[nums[i] - i] || 0) + 1;
    }
    let res = 0;
    let len = nums.length;
    for(let key in flag){
        res += (len - flag[key]) * flag[key];
    }
    return res / 2;
};
复制代码

说在后面

🎉这里是JYeontu,喜欢算法,GDCPC打过卡;热爱羽毛球,大运会打过酱油。毕业一年,两年前端开发经验,目前担任H5前端开发,算法业余爱好者,有空会刷刷算法题,平时喜欢打打羽毛球🏸 ,也喜欢写些东西,既为自己记录📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解🙇,写错的地方望指出,定会认真改进😊,在此谢谢大家的支持,我们下文再见🙌。

分类:
前端
收藏成功!
已添加到「」, 点击更改