关于剑指 Offer 40. 最小的k个数的相关问题
波波老师,您好!
我先贴出来我的代码(基本和您的吻合)
相关代码:
/// Leetcode 剑指 Offer 40. 最小的k个数
/// https://leetcode.cn/problems/kth-largest-element-in-an-array/
import java.util.Arrays;
import java.util.Random;
class Solution {
public int[] getLeastNumbers(int[] nums, int k) {
Random rnd = new Random();
selectK(nums, 0, nums.length - 1, k - 1, rnd);
return Arrays.copyOf(nums, k);
}
private int selectK(int[] nums, int l, int r, int k, Random rnd) {
int p = partition(nums, l, r, rnd);
if (k == p) return nums[p];
if (k < p) return selectK(nums, l, p - 1, k, rnd);
return selectK(nums, p + 1, r, k, rnd);
}
private int partition(int[] nums, int l, int r, Random rnd) {
int p = l + rnd.nextInt(r - l + 1);
swap(nums, l, p);
// arr[l+1...i-1] <= v; arr[j+1...r] >= v
int i = l + 1, j = r;
while (true) {
while (i <= j && nums[i] < nums[l])
i++;
while (j >= i && nums[j] > nums[l])
j--;
if (i >= j) break;
swap(nums, i++, j--);
}
swap(nums, l, j);
return j;
}
private void swap(int[] nums, int i, int j) {
int t = nums[i];
nums[i] = nums[j];
nums[j] = t;
}
}测试用例是:
public class Main {
public static void main(String[] args) {
int[] nums = {0, 0, 0, 2, 0, 5};
Solution solution = new Solution();
int[] numbers = solution.getLeastNumbers(nums, 0);
for (int i = 0; i < numbers.length; i++)
System.out.print(numbers[i] + " ");
}
}报错是:



我的调试过程:
传入的数组是
{0, 0, 0, 2, 0, 5}传入的参数是0
selectK(nums.0,5,-1,rnd)
partition(nums,0,5,rnd):p=2,返回值为j=2
{0, 0, , 2, 0, 5}
k(-1)<p(j=2),selectK(nums,0,1,-1,rnd)
partition(nums,0,1,rnd):p=1,返回值为j=1
{0, , 0, 2, 0, 5}
k(-1)<p(j=1),selectK(nums,0,0,-1,rnd)
partition(nums,0,0,rnd):p=0,返回值为j=0
{, 0, 0, 2, 0, 5}
k(-1)<p(j=0),selectK(nums,0,-1,-1,rnd)
partition(nums,0,-1,rnd):在这里的第一行取随机数的代码就会出现索引问题

==============分界线================
波波老师,主要我觉得似乎在处理k=0的时候,无论数组是如何的,似乎都会出现这种问题。。。
下面是老师您的代码:

正在回答 回答被采纳积分+1
需要对 k == 0 的情况做一个特判。加上下面一句话即可:
public int[] getLeastNumbers(int[] nums, int k) {
if(k == 0) return new int[0]; // 加上这句话
Random rnd = new Random();
selectK(nums, 0, nums.length - 1, k - 1, rnd);
return Arrays.copyOf(nums, k);
}我们的 selectK(nums, l, r, k) 函数的语义是,在 nums 的 [l, r] 区间中,找到索引为 k 的元素。这个索引 k 必须是合法的。如果 k = 0,传入 k - 1,也就是传进 selectK 的 k 是 -1,是一个非法索引。
==========
这个“边界”测试用例很没有意思。因为返回最小的 0 个数字没有意义。最小的 0 个数字肯定就是什么都没有。我们特殊添加的一句话就是返回了一个含有 0 个元素的数组而已。
我忘记了这个测试用例是不是本身就有的测试用例,还是后来添加的。我怀疑是后来添加的。因为课程的代码在发布的时候,都经过我的测试的。
继续加油!:)
相似问题
登录后可查看更多问答,登录/注册
恭喜解决一个难题,获得1积分~
来为老师/同学的回答评分吧
0 星