1. 题目解析与问题定义
LeetCode 1385题要求我们计算两个数组间的"距离值"。题目给定两个整数数组arr1和arr2,以及一个整数d。距离值的定义是:arr1中满足"对于arr2中的每一个元素,arr1[i]与arr2[j]的绝对差都大于d"的元素个数。
换句话说,我们需要统计arr1中有多少个元素,这些元素与arr2中所有元素的差值绝对值都大于d。这相当于在arr1中筛选出那些"远离"arr2所有元素的数字。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 暴力解法思路分析
最直观的解法是暴力双重循环:
- 遍历arr1中的每个元素
- 对于每个arr1[i],遍历arr2中的所有元素
- 检查是否所有|arr1[i]-arr2[j]| > d
- 如果全部满足,则计数器加1
这种解法的时间复杂度是O(n*m),其中n和m分别是arr1和arr2的长度。虽然在小数据量时可行,但当数组较大时效率会明显下降。
3. 优化思路:排序与二分查找
我们可以通过预处理arr2来优化算法:
- 首先对arr2进行排序(O(m log m))
- 对于每个arr1[i],在排序后的arr2中使用二分查找找到最接近arr1[i]的元素
- 只需要检查这几个邻近元素是否满足|arr1[i]-arr2[j]| > d
- 如果邻近元素都满足,则更远的元素自然满足
这种优化将时间复杂度降低到O((n+m)log m),显著提高了效率。
4. 具体实现步骤
4.1 排序arr2
python复制arr2.sort()
4.2 实现二分查找
我们需要找到arr2中与arr1[i]最接近的元素:
python复制def find_closest(arr, target):
left, right = 0, len(arr) - 1
while left <= right:
mid = (left + right) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return left
4.3 检查距离条件
对于每个arr1[i],找到其在arr2中的插入位置,然后检查邻近元素:
python复制count = 0
for num in arr1:
idx = find_closest(arr2, num)
valid = True
# 检查邻近的几个位置
for j in [idx-1, idx, idx+1]:
if 0 <= j < len(arr2) and abs(num - arr2[j]) <= d:
valid = False
break
if valid:
count += 1
return count
5. 边界条件处理
在实际实现中需要注意以下边界情况:
- 空数组处理:如果arr1或arr2为空,结果应该是0或len(arr1)
- 单个元素数组:需要特殊处理
- 重复元素:算法应能正确处理
- 极端d值:d=0或d非常大时的特殊情况
6. 复杂度分析
-
时间复杂度:
- 排序arr2:O(m log m)
- 对于每个arr1元素进行二分查找:O(n log m)
- 总复杂度:O((n + m) log m)
-
空间复杂度:
- 排序可能需要O(log m)的栈空间(取决于排序算法)
- 其他操作使用常数空间
- 总空间复杂度:O(1)
7. 实际测试与优化
在实际测试中,我们发现:
- 对于小数组(n,m<100),暴力法和优化法差异不大
- 对于大数组(n,m>10000),优化法速度可提升10倍以上
- 可以进一步优化:
- 提前终止检查:一旦发现不满足条件的元素立即跳出
- 并行处理:对arr1的不同部分使用多线程处理
8. 常见错误与调试技巧
在解决这个问题时,容易犯以下错误:
- 忘记处理边界条件(空数组、单个元素等)
- 二分查找实现不正确导致死循环或错误结果
- 没有正确理解题目中的"所有"条件
- 在优化解法中检查的邻近元素数量不足
调试技巧:
- 使用小测试用例手动验证
- 打印中间结果检查二分查找是否正确
- 对特殊边界条件单独测试
9. 类似题目推荐
掌握这个问题后,可以尝试以下类似题目:
- LeetCode 349. Intersection of Two Arrays
- LeetCode 350. Intersection of Two Arrays II
- LeetCode 658. Find K Closest Elements
- LeetCode 1337. The K Weakest Rows in a Matrix
这些题目都涉及数组操作和二分查找的应用,是巩固相关技能的很好练习。
10. 个人实现心得
在实际编码中,我发现以下几点特别重要:
- 先写暴力解法确保理解题意正确
- 画图辅助理解二分查找的过程
- 使用Python的bisect模块可以简化二分查找实现
- 测试时要包含极端情况(如最大/最小值、重复元素等)
对于追求极致性能的情况,可以考虑:
- 使用更高效的排序算法
- 用C++等更底层的语言实现
- 利用SIMD指令并行化部分计算
