在这篇文章中,我们需要解决一道关于序列的第k小数问题,给定一个长度为n的整数序列a,找到区间[l,r](区间长度大于等于k),计算这个区间第k小的数等于x的(l,r)有多少对。
首先,我们可以采用直接遍历的方法,利用双层for循环遍历每个长度大于等于k的数组,再对其排序,判断第k小的数是不是x,如果是,则计算数组中小于x的个数。具体实现如下;
function solution(n, x, k, a) {
let count = 0;
// 辅助函数,用于计算数组中小于等于value的元素个数
function countNum(nums, value) {
let count = 0;
for (let num of nums) {
if (num <= value) count++;
}
return count;
}
// 遍历数组,寻找所有可能的(l, r)对
for (let l = 0; l <= n - k; l++) {
for (let r = l + k - 1; r < n; r++) {
// 切片数组从l到r(包括r)
let subArray = a.slice(l, r + 1);
// 对子数组进行排序
let sortedArr = [...subArray].sort((a, b) => a - b);
// 找到子数组中第k小的数的位置
let index = k - 1;
// 检查第k小的数是否等于x
if (sortedArr[index] === x) {
// 检查子数组中小于等于x的元素个数是否至少为k
if (countNum(sortedArr, x) >= k) {
count++;
}
}
}
}
return count;
}
定义一个solution方法接收参数n数组长度,x第k小的数,k子数组长度最小值,a数组,然后定义一个count用于记录符合要求的个数,开始遍历数组,通过两层嵌套for循环,外层循环变量 l 表示区间的左端点,内层循环变量 r 表示区间的右端点,在每次内层循环中,代码会提取区间 [l, r] 的子数组 subArray,然后对子数组进行排序,得到 sortedArr,计算子数组中第k小的数的位置,即 index = k - 1,再判断如果第k小的数等于 x,则使用 countNum 函数检查子数组中小于等于 x 的元素个数是否至少为 k。如果满足,则count++,最后return。
除此,还可用双指针的方法解决。先定义一个window数组窗口,利用双指针左边界l和右边界r,将当前元素加入窗口,判断确保当前窗口长度不小于k的情况下,对当前窗口进行排序,判断第k小的数是否为x,若是,则加1。具体实现如下;
function solution(n, x, k, a) {
let count = 0;
// 使用双指针 l 和 r
for (let l = 0; l < n; l++) {
const window = [];
for (let r = l; r < n; r++) {
// 将当前元素加入窗口
window.push(a[r]);
// 确保窗口长度不小于 k
if (r - l + 1 >= k) {
// 对当前窗口进行排序
const sortedWindow = [...window].sort((a, b) => a - b);
// 获取第 k 小的数
if (sortedWindow[k - 1] === x) {
count++;
}
}
}
}
return count;
}
const sortedWindow = [...window].sort((a, b) => a - b);
这样做的目的是为了在不改变原始 window 数组的情况下,对其进行排序,如果直接window 数组调用 sort() 方法,会改变原数组的顺序。例如查找第 k 小的元素。这样做可以保证我们在处理窗口的数据时不会影响原来的窗口状态。
个人总结:
双指针基本概念:
- 两个指针:通常使用两个指针(例如
left和right),这两个指针可以从不同的端点开始移动,或者一个固定,另一个在变化。 - 滑动窗口:在处理子数组或子序列时,一个常用的方法是将一个指针固定在起始位置,而另一个指针滑动到结束位置,这样可以有效地维护当前子结构的状态。
- 条件更新:根据某些条件(如累积和、元素数量等),动态调整指针的位置,以便找到符合要求的结果。
主要使用场景:
- 查找配对:在有序数组中查找两个数之和为目标值的配对。
- 最小/最大子数组/子序列:寻找满足条件的最小或最大长度的子数组。
- 去重与分组:处理重复元素,或将数组分成两部分等。
- 字符串处理:判断是否是回文串、去除重复字符等。
双指针是一种常见的算法技巧,通常用于解决数组或链表相关的问题。它可以减少不必要的遍历次数,逻辑清晰明了,便于掌握和应用。