【剑指offer】40. 最小的k个数

题目描述

在这里插入图片描述

在这里插入图片描述

// 力扣
// 输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、
// 2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。

// 牛客
// 输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字
// ,则最小的4个数字是1,2,3,4。

题解

// 暴力法 //

// 力扣
// 暴力法,能通过但没有意义
// 执行用时:8 ms, 在所有 Java 提交中击败了64.97%的用户
// 内存消耗:40 MB, 在所有 Java 提交中击败了17.80%的用户
import java.util.Arrays;
class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
		int[] res = new int[k];
		Arrays.sort(arr);
		for (int i = 0; i < k; i++) {
			res[i] = arr[i];
		}
		return res;
    }
}

如果用数组表示堆的话,根据层序顺序标号规则,将层序标号对应到数组索引中,那么在数组索引中找二叉树左右结点可以通过如下规律:找结点的左节点:索引2,找结点的右结点:索引2+1,找结点的父结点:索引 / 2(整数除法,要去除小数点)。
在这里插入图片描述

/// 最大堆法 ///
// 比较好的方法


// 牛客
// 运行时间:15ms
// 占用内存:9944k
import java.util.ArrayList;
import java.util.PriorityQueue;  // 利用优先队列构建堆
import java.util.Comparator;  // 比较器
public class Solution {
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        if (k > input.length || k < 0)  // 如果k值有问题,返回空数组
            return new ArrayList<>();
		// 优先队列默认是最小堆(最小值置顶),将其修改成最大堆(最大值置顶)
        // 得到构建好的最大堆maxHeap
		PriorityQueue<Integer> maxHeap = new PriorityQueue<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2.compareTo(o1);
            }
        });
		// for循环遍历input中的元素,将其放入num中
        for (int num: input) {
            maxHeap.add(num);
			// 由于是最大堆,所以最大值一定会被置顶
			// 当堆中元素超过k(达到k+1)了,那么置顶元素一定比其余k个数大,
			// 将其弹出。input所有元素被遍历过,且在堆中被比较过大小,
			// 所以能在堆中留下的k个数就是input里最小的k个数。
            if (maxHeap.size() > k)  
                maxHeap.poll();
        }
		// 将堆以ArrayList格式返回
        return new ArrayList<>(maxHeap);
    }
}


// 力扣
// 执行用时:25 ms, 在所有 Java 提交中击败了13.48%的用户
// 内存消耗:39.6 MB, 在所有 Java 提交中击败了77.55%的用户
import java.util.ArrayList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Comparator;
class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
        if (k > arr.length || k <= 0)
            return new int[0];
        PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2.compareTo(o1);
            }
        });
        for (int num: arr) {
            maxHeap.add(num);
            if (maxHeap.size() > k)
                maxHeap.poll();
        }
        int[] res = new int[k];
        ArrayList<Integer> kmin = new ArrayList<>(maxHeap);
        toResList(kmin, res, k);
        return res;
    }

    public void toResList(ArrayList<Integer> kmin, int[] res, int k) {
        for (int i = 0; i < kmin.size(); i++) {
            res[i] = kmin.get(i);
        }
    }
}

// 力扣
// 执行用时:27 ms, 在所有 Java 提交中击败了11.67%的用户
// 内存消耗:40.1 MB, 在所有 Java 提交中击败了8.06%的用户
import java.util.ArrayList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Comparator;
class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
        if (k > arr.length || k <= 0)
            return new int[0];
        PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2.compareTo(o1);
            }
        });
        for (int num: arr) {
            maxHeap.add(num);
            if (maxHeap.size() > k)
                maxHeap.poll();
        }
        int[] res = new int[k];
        toResList(maxHeap, res);
        return res;
    }

    public void toResList(PriorityQueue<Integer> maxHeap, int[] res) {
		int i = 0;
		for (int num : maxHeap) {
			res[i++] = num;
		}
    }
}


/ 快速选择法 /
// 快速选择和快排很类似

// 牛客
// 运行时间:14ms
// 占用内存:9924k
import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
		ArrayList<Integer> res = new ArrayList<>();
		if (k > input.length || k <= 0) 
			return res;
		findKthSmallest(input, k);  // 快选主函数
		// 此时input前k个元素即为最小的k个元素
		for (int i = 0; i < k; i++)  
			res.add(input[i]);  // 将前k个元素存入res中
		return res;
    }	
	
	// 快速选择函数
	// 找k个最小值
	public void findKthSmallest(int[] input, int k) {
		int low = 0, high = input.length - 1;  // 初始化左右边界
		while (low < high) {
			int size = partition(input, low, high);
			if (size == k)  // 直到size等于k,停止循环
				break;
			if (size > k) // 最小的k个数一定在前size个数中
				high = size - 1;  // 右边界high左移
			else // size < k   // 在右侧数组中继续找最小的k个数
				low = size + 1;  // 左边界low右移
		}
	}
	
	// 切分函数,我们希望使数组切分值的左边都是小元素,右边都是大元素
	private int partition(int[] input, int low, int high) {
		int split = input[low];  // 切分值初始化
		int i = low, j = high + 1;  // 双指针i,j遍历input元素
		while (true) {
			// i从左往右移,遍历到不小于split的元素为止
			while (i != high && input[++i] < split);
			// j从右往左移,遍历到不大于split的元素位置
			while (j != low && input[--j] > split);
			if (i >= j)
				break;
			// input[i]比split大,input[j]比split小,交换位置
			swap(input, i, j);  
		}
		swap(input, low, j);  // input[j]比split值本身要小,交换位置
		return j;  // 返回
	}
	
	// 交换函数
	private void swap(int[] input, int i, int j) {
		int t = input[i];
		input[i] = input[j];
		input[j] = t;
	}
}


// 力扣
// 执行用时:3 ms, 在所有 Java 提交中击败了83.07%的用户
// 内存消耗:39.8 MB, 在所有 Java 提交中击败了51.36%的用户
import java.util.ArrayList;
class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
        if (k > arr.length || k <= 0)
            return new int[0];
		findKSmallest(arr, k);
		int[] res = new int[k];
		for (int i = 0; i < k; i++) {
			res[i] = arr[i];
		}
		return res;
    }
	
	public void findKSmallest(int[] arr, int k) {
		int low = 0, high = arr.length - 1;
		while (true) {
			int size = partition(arr, low, high);
			if (size == k)
				break;
			if (size > k)
				high = size - 1;
			else 
				low = size + 1;
		}
	}
	
	private int partition (int[] arr, int low, int high) {
		int split = arr[low];
		int i = low, j = high + 1;
		while (true) {
			while (i < high && arr[++i] < split);
			while (j > low && arr[--j] > split);
			if (i >= j)
				break;
			swap(arr, i, j);
		}
		swap(arr, low, j);
		return j;
	}
	
	private void swap(int[] arr, int i, int j) {
		int temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}
}

猜你喜欢

转载自blog.csdn.net/fisherish/article/details/113070679
今日推荐