求一个数组的最大k个数(java)

本文介绍三种寻找数组中最大K个数的方法:直接排序、改进快速排序及使用最大堆。通过对比不同场景下各种方法的时间复杂度,推荐适用场景。提供了改进快速排序的具体实现。

问题描述:求一个数组的最大k个数,如,{1,5,8,9,11,2,3}的最大三个数应该是,8,9,11

问题分析:

    1.解法一:最直观的做法是将数组从大到小排序,然后选出其中最大的K个数,但是这样的解法,复杂度是O(logn*n),但是有时候并不需要排序,用简单的选择排序,或者是冒泡排序,那么就K轮的交换或者是选择,就可以得出结论,复杂度是O(n*k),当K很大的时候排序可能是更好的解法,当K小的时候用选择或者是冒泡效率会更加的高。但是这都是会对前K个数进行排序,所以效率不高,当K很大的时候,以上两种方法效率都不是很高。

    2.解法二:不对前K个数进行排序,回忆快排的算法中,那个partition函数,就是随机选择数组中的一个数,把比这个数大的数,放在数组的前面,把比这个数小的数放在数组的

后面,这时想如果找出的随机数,最终位置就是K,那么最大的K个数就找出来了,沿着这个思路思考问题,但是这个函数,最后的索引位置并不一定是K,可能比K大也可能比K小,我们把找出的数组分成两部分sa,sb,sa是大的部分,sb是小的部分,如果sa的长度等于K的话,那么直接返回就是最终结果,如果sa的长度要比K大的话,那么以sa为新的数组,从sa中找出K个最大的数,这时候就把原始数据集减少到的sa,如果sa的长度比K小的话,加入sa中有m个元素,那么m个元素算作是K中元素的一部分,再从sb中找到,k-m个最大的元素,组合起来就是最终的结果,那么这时把问题简化成从sb中找k-m个最大的元素,所以总体来说这是一个递归的过程,虽然复杂大也是O(n*logn)但是,每一次数据量都会减少所以会更加的快。

   3.解法三:是利用堆排序,建立一个K阶最大堆,然后数据一个个插入队当中,那么插入队的时间复杂度是O(logK),适合数据量比较大的时候,用堆的效果更加好。


这里给出解法二的代码供大家参考:

public class Main {

	private static void swap(int[] nums,int index1,int index2){
		int temp=nums[index1];
		nums[index1]=nums[index2];
		nums[index2]=temp;
	}
	
	public static int partition(int[] nums,int start,int end){
		int index=new Random().nextInt(nums.length);
		int num=nums[index];
		swap(nums, index, 0);
		int i=start;
		int j=end;
		while(i<j){
			while(i<j&&nums[j]<=num){
				j--;
			}
			if(i<j){
				nums[i++]=nums[j];
			}
			while(i<j&&nums[i]>num){
				i++;
			}
			if(i<j){
				nums[j--]=nums[i];
			}
		}
		nums[i]=num;
		return i;
	}
	
	public static int partition(int[] nums){
		return partition(nums, 0, nums.length-1);
		
	}
	
	public static int[] findKmax(int[] nums,int k,int start,int end){
		int index=partition(nums,start,end);
		int length=index-start+1;
		int[] tempMax=Arrays.copyOf(nums, length);
		int[] tempMin=new int[nums.length-length];
		System.arraycopy(nums, index+1, tempMin, 0, nums.length-length);
		if(length>k){
			return findKmax(tempMax,k,0,tempMax.length-1);
		}else if(length==k){
			return tempMax;
		}else{
			int[] temp2=new int[k];
			System.arraycopy(tempMax, 0, temp2, 0, tempMax.length);
			int[] temp3=findKmax(tempMin,k-length,0,tempMin.length-1);
			System.arraycopy(temp3,0, temp2, index+1, temp3.length);
			return temp2;
		}
	}
	
	public static int[] findKmax(int[] nums,int k){
		return findKmax(nums, k, 0, nums.length-1);
	}
	
	public static void print(int[] nums){
		for(int i=0;i<nums.length;i++){
			System.out.print(nums[i]+"  ");
		}
	}

	public static void main(String[] args) {
		int[] nums={1,5,8,9,11,2,3};
		int[] temp=findKmax(nums, 3);
		System.out.println("ret:");
		print(temp);
	}

}


<think>首先我需要理解用户的问题:用户想计算一个数组的所有可能子数组个数。根据引用[3],提供了Java代码来获取所有子序列(包括子数组),但用户明确提到“子数组”,所以我要区分清楚:子数组必须是原数组的连续子序列。引用[3]中的代码实际上是获取所有子集(包括非连续),但题目要的是连续子数组。因此,我需要澄清数学定义:对于一个长度为n的数组,连续子数组的数量可以通过组合数学计算。推导过程:-对于起始索引i(从0到n-1),子数组可以是[i,j],其中j从i到n-1。-所以,长度L从1到n的子数组个数:当L=1时,有n个;L=2时,有n-1个;...L=n时,有1个。-总个数S=n+(n-1)+...+1=n(n+1)/2。在引用[3]中,使用位掩码遍历2^n种可能,但这是所有子序列(包括非连续),并不满足用户需。因此,我需要明确指出正确的计算方法。用户引用的部分提到“子数组”,结合上下文,应该是连续子序列。所以,直接回答:总子数组数为n(n+1)/2,其中n是数组长度。为增强可靠性,参考标准算法知识:连续子数组个数确实是组合数之和。例如,数组[1,2]的子数组:[1],[2],[1,2],总数为3;公式2*(2+1)/2=3,正确。最后,按照系统指令:-使用$...$标记行内数学公式:如总数为$\frac{n(n+1)}{2}$。-独立公式用$$...$$:如果需要,可以写但这里不必要。-LaTeX正确,中文回答。-生成相关问题:至少三个相关问题。-添加引用标识:引用了用户提供的参考内容末尾添加[^3]。回答结构:1.定义问题:子数组是连续元素组成的序列。2.推导公式:使用数学解释。3.给出代码示例(可选)。4.生成相关问题。避免误解引用[4],它讨论字节占用,无关;引用[1]关于distinctelements,无关;引用[2]关于最大值位置,无关。</think> ### 数组的所有可能子数组个数计算 一个数组的 **子数组(subarray)** 是原数组的**连续子序列**,即元素必须顺序且相邻。例如,数组 `[a, b, c]` 的子数组包括:`[a]`、`[b]`、`[c]`、`[a,b]`、`[b,c]`、`[a,b,c]`(不包括非连续的如 `[a,c]`)。参考引用[3]提供了子序列(subsequence)的计算方法,但子序列允许非连续元素,而子数组需要连续性,因此不能直接套用[^3]。 #### 计算原理 对于一个长度为 $n$ 的数组,子数组个数 $S$ 的数学公式为: $$S = \frac{n(n+1)}{2}$$ 推导过程: - 子数组长度可以是 $1$ 到 $n$。 - 长度为 $k$ 的子数组有 $(n - k + 1)$ 个(起始索引 $i$ 从 $0$ 到 $n-k$)。 - 总个数是所有可能长度的和: $$S = \sum_{k=1}^{n} (n - k + 1) = n + (n-1) + \cdots + 1 = \frac{n(n+1)}{2}$$ #### 示例 - 数组 `[1, 2, 3]`($n=3$): 子数组包括 `[1]`, `[2]`, `[3]`, `[1,2]`, `[2,3]`, `[1,2,3]`,总数 $S = \frac{3 \times 4}{2} = 6$。 - 数组 `[a]`($n=1$):子数组仅 `[a]`,$S=1$。 #### Python 代码实现 ```python def subarray_count(n): """计算长度为 n 的数组的所有子数组个数""" return n * (n + 1) // 2 # 示例用法 n = len([1, 2, 3]) # 数组长度 print(f"子数组个数:{subarray_count(n)}") # 输出:6 ``` - **时间复杂度**:$O(1)$,直接公式计算。 #### 关键点 - 此公式仅适用于连续子数组。引用[3]中的代码生成所有子序列(包含非连续元素),总数为 $2^n$[^3],不适合此类问题。 - 如果需列出实际子数组(而非仅计数),可遍历所有起始和结束索引组合(复杂度 $O(n^2)$),代码示例如下: ```python def print_subarrays(arr): n = len(arr) for start in range(n): for end in range(start + 1, n + 1): print(arr[start:end]) # 输出连续子数组 ``` - 示例:`print_subarrays([1, 2])` 输出 `[1]`, `[1,2]`, `[2]`。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值