[Sword refers to offer] 40. The smallest number of k

Title description

Insert picture description here

Insert picture description here

// 力扣
// 输入整数数组 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。

answer

// 暴力法 //

// 力扣
// 暴力法,能通过但没有意义
// 执行用时: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;
    }
}

If an array is used to represent the heap, and the layer sequence label corresponds to the array index according to the layer sequence labeling rules, then the following rules can be used to find the left and right nodes of the binary tree in the array index: find the left node of the node: index 2, find The right node of the node: index 2+1, find the parent node of the node: index/2 (integer division, remove the decimal point).
Insert picture description here

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


// 牛客
// 运行时间: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;
	}
}

Guess you like

Origin blog.csdn.net/fisherish/article/details/113070679