当前位置: 首页 > news >正文

千问 LeetCode 2426.满足不等式的数对数目 public long numberOfPairs(int[] nums1, int[] nums2, int diff)

这道题的核心在于将不等式变形,转化为一个经典的“顺序对”计数问题,然后利用树状数组或归并排序高效求解。


1. 核心思路:不等式变形

题目要求: nums1[i] - nums1[j] <= nums2[i] - nums2[j] + diff ,且 i < j 。

将含有 i 和 j 的项分别移到不等式两边:
nums1[i] - nums2[i] <= nums1[j] - nums2[j] + diff

定义一个新数组 nums ,其中 nums[k] = nums1[k] - nums2[k] 。

那么原问题就等价于:在数组 nums 中,找到所有满足 i < j 且 nums[i] <= nums[j] + diff 的数对 (i, j) 的个数。


2. 解法:树状数组(Fenwick Tree)

我们可以从左到右遍历数组 nums ,对于当前遍历到的位置 j ,我们需要统计在它之前(即 i < j )有多少个 nums[i] 满足 nums[i] <= nums[j] + diff 。

具体步骤:

离散化:由于 nums[i] 和 nums[j] + diff 的值范围可能很大,我们需要将所有可能出现的值( nums[i] 和 nums[i] + diff )进行排序和去重,映射到连续的索引上。

遍历与查询:

从左到右遍历 nums 。

对于当前元素 num = nums[j] ,我们查询树状数组中所有小于等于 num + diff 的元素个数。这相当于查询 num + diff 在离散化数组中的位置,然后求前缀和。

将查询结果累加到答案 ans 中。

将当前元素 num 插入到树状数组中(在 num 对应的离散化索引位置加1),供后续元素查询。

代码实现(Java):

class Solution {
public long numberOfPairs(int[] nums1, int[] nums2, int diff) {
int n = nums1.length;
int[] nums = new int[n];
for (int i = 0; i < n; i++) {
nums[i] = nums1[i] - nums2[i];
}

// 1. 离散化:收集所有可能出现的值
Set<Integer> set = new HashSet<>();
for (int num : nums) {
set.add(num);
set.add(num + diff); // 因为我们要查询 <= num + diff
}
List<Integer> sorted = new ArrayList<>(set);
Collections.sort(sorted);
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < sorted.size(); i++) {
map.put(sorted.get(i), i + 1); // 树状数组索引从1开始
}

// 2. 树状数组
int m = sorted.size();
int[] bit = new int[m + 1];
long ans = 0;

for (int num : nums) {
// 查询 <= num + diff 的元素个数
int idx = map.get(num + diff);
ans += query(bit, idx);
// 插入当前元素
update(bit, map.get(num), 1);
}
return ans;
}

private void update(int[] bit, int i, int delta) {
while (i < bit.length) {
bit[i] += delta;
i += i & -i;
}
}

private int query(int[] bit, int i) {
int sum = 0;
while (i > 0) {
sum += bit[i];
i -= i & -i;
}
return sum;
}
}

3. 解法:归并排序(Merge Sort)

在归并排序的过程中,我们可以利用左右两个子数组已经有序的特性,高效地统计跨过中点的数对。

具体步骤:

将数组 nums 递归地分成两半。

先递归统计左半部分和右半部分内部的数对。

统计跨过中点的数对:

假设左半部分为 [left, mid] ,右半部分为 [mid+1, right] ,且它们内部已经排好序。

对于左半部分的每个元素 nums[i] ,我们需要在右半部分中找到第一个满足 nums[j] + diff < nums[i] 的元素(即不满足条件的元素),那么右半部分中从该元素到末尾的所有元素都满足条件。

使用双指针(或二分查找)来加速这个过程。

合并两个有序数组。

代码实现(Java):

class Solution {
private long ans = 0;
private int[] temp;

public long numberOfPairs(int[] nums1, int[] nums2, int diff) {
int n = nums1.length;
int[] nums = new int[n];
for (int i = 0; i < n; i++) {
nums[i] = nums1[i] - nums2[i];
}
temp = new int[n];
mergeSort(nums, 0, n - 1, diff);
return ans;
}

private void mergeSort(int[] nums, int left, int right, int diff) {
if (left >= right) return;
int mid = left + (right - left) / 2;
mergeSort(nums, left, mid, diff);
mergeSort(nums, mid + 1, right, diff);

// 统计跨过中点的数对
int j = mid + 1;
for (int i = left; i <= mid; i++) {
while (j <= right && nums[j] + diff < nums[i]) {
j++;
}
ans += right - j + 1;
}

// 合并两个有序数组
int i = left, k = left;
j = mid + 1;
while (i <= mid && j <= right) {
if (nums[i] <= nums[j]) {
temp[k++] = nums[i++];
} else {
temp[k++] = nums[j++];
}
}
while (i <= mid) temp[k++] = nums[i++];
while (j <= right) temp[k++] = nums[j++];
System.arraycopy(temp, left, nums, left, right - left + 1);
}
}
总结

树状数组:思路更直接,适合在面试中快速写出,但需要离散化处理。

归并排序:不需要离散化,代码稍长,但常数更小,速度更快。

两种解法的时间复杂度都是 O(n log n),空间复杂度为 O(n)。

http://www.jsqmd.com/news/833451/

相关文章:

  • DownKyi终极指南:三步掌握B站8K视频下载的完整解决方案
  • Godot 4网络同步框架MonkeNet:组件化架构与权威服务器实践
  • 父类 = new 子类,编译看左面,运行看右面,这是多态的精髓与必要性。为啥不写成子类 = new 子类?一文详解
  • 2026医康养设计公司:赋能健康产业融合发展新路径 - 品牌排行榜
  • 千问 LeetCode 2426.满足不等式的数对数目 Go实现
  • 出口型工厂从外部就能认出来吗?8 个不进门就能验证的特征清单
  • 阴阳师自动化脚本OAS终极指南:轻松解放双手的完整教程
  • 从零构建本地化AI代码助手:架构、微调与工程实践
  • 5分钟掌握B站视频转文字:免费开源的终极解决方案
  • Jetson Orin上编译Apollo遇到‘drm.h找不到’?手把手教你修复Bazel编译依赖
  • 开源技能库构建指南:Git+Markdown+Docsify打造个人技术知识体系
  • 基于Docker部署OpenOffice无头服务实现文档自动化处理
  • 什么是适配器模式?一文详解
  • Supabase AI Agent技能库:安全集成数据库操作与边缘函数调用
  • 赊账前先看 6 个信号:怎么提前判断一家工厂会不会跑路、烂尾、收不回货款
  • 从零构建数据同步中间件:插件化架构与工程实践全解析
  • UVa 366 Cutting Up
  • 3个维度重塑:如何用UABEA解锁Unity资源编辑新可能?
  • 前端工程化实战:基于 Kelivo 模板的配置即代码与自动化工作流
  • 猫抓cat-catch:浏览器媒体资源嗅探与流媒体解析技术深度解析
  • SyntaxUI:基于原子设计与Web组件的现代UI库开发实践
  • 利用OCI免费套餐构建高可用Kubernetes集群实战指南
  • 工厂的招工动态能看出哪些经营信息?一份给上游销售员的信号解读手册
  • 百度网盘直链解析终极指南:3步实现高速下载的技术原理与实战
  • 合宙Air153C看门狗芯片:嵌入式系统可靠性的硬件守护方案
  • Gitclaw:封装复杂Git操作,提升开发效率的命令行工具
  • 野火挑战者V2开发板网络通信避坑记:从Ping不通到TCP热插拔,我的STM32F429+LAN8720A调试实录
  • Godot引擎集成Discord RPC:实现游戏状态实时展示与社区互动
  • 基于Plan 9与Lua的9router:构建统一命名空间的网络服务框架
  • DLSS Swapper:游戏性能优化的智能管家,释放显卡潜能的终极利器