//题目:寻找数组中最大的k个数
//解法1:使用快排或选择排序,快排完成的复杂度O(NlogN),选择排序O(N*K)
public class Main {
public static void main(String[] args) throws Exception {
int[] result1 = findMaxKNum1(new int[]{3,4,5,3,2,1,6,8},3);
int[] result2 = findMaxKNum2(new int[]{3,4,5,3,2,1,6,8},3);
for(int i = 0;i<result1.length;i++){
System.out.print(result1[i]+" ");
}
System.out.println();
for(int i = 0;i<result2.length;i++){
System.out.print(result2[i]+" ");
}
}
//选择排序O(N*K) 因为只需要进行K趟排序
public static int[] findMaxKNum1(int[] input, int k) throws Exception {
for(int i = 0;i<k;i++){
int index = i;
for(int j = i+1;j<input.length;j++){
if(input[index]<input[j]){
index = j;
}
}
if(index!=i){
int temp = input[index];
input[index] = input[i];
input[i] = temp;
}
}
int[] result = new int[k];
for(int i = 0;i<k;i++){
result[i] = input[i];
}
return result;
}
//快速排序O(N*logN)需要全部排序完毕才能选择最大的k个
public static int[] findMaxKNum2(int[] input, int k) throws Exception {
sort(input, 0, input.length-1);
int[] result = new int[k];
for(int i = 0;i<k;i++){
result[i] = input[i];
}
return result;
}
public static void sort(int[] input, int low, int high){
if(low<high){
int mid = partition(input, low, high);
sort(input,low,mid-1);
sort(input,mid+1,high);
}
}
public static int partition(int[] input, int low, int high){
int temp = input[low];
while(low<high){
while(low<high && temp>=input[high]){
high--;
}
input[low] = input[high];
while(low<high && temp<=input[low]){
low++;
}
input[high] = input[low];
}
input[low] = temp;
return low;
}
}
//解法2:采用类似于快排的方式,每次返回mid点,如果mid为k则直接取前k个元素,否则根据mid与k的比较情况决定递归的方向 O(N*logK)
public class Main {
public static void main(String[] args) throws Exception {
int[] result1 = findMaxKNum1(new int[]{3,4,5,3,2,1,6,8},3);
for(int i = 0;i<result1.length;i++){
System.out.print(result1[i]+" ");
}
System.out.println();
}
public static int[] findMaxKNum1(int[] input, int k) throws Exception {
int mid = partition(input, 0, input.length-1);
while(mid!=k){
if(mid<k){
mid = partition(input,mid+1,input.length-1);
}else{
mid = partition(input,0,mid-1);
}
}
int[] result = new int[k];
for(int i = 0;i<k;i++){
result[i] = input[i];
}
return result;
}
public static int partition(int[] input, int low, int high){
int temp = input[low];
while(low<high){
while(low<high && temp>=input[high]){
high--;
}
input[low] = input[high];
while(low<high && temp<=input[low]){
low++;
}
input[high] = input[low];
}
input[low] = temp;
return low;
}
}
//解法3:建立一个大小为K的堆,每次将这个堆中的元素进行排序,将之后的元素与堆中最小的元素进行比较,如果比堆中元素大,则将其加入堆中
public class Main {
public static void main(String[] args) throws Exception {
int[] result1 = findMaxKNum1(new int[]{3,4,5,3,2,1,6,8},3);
for(int i = 0;i<result1.length;i++){
System.out.print(result1[i]+" ");
}
System.out.println();
}
public static int[] findMaxKNum1(int[] input, int k) throws Exception {
buildMinHeap(input,k);
for(int i = k;i<input.length;i++){
if(input[0] < input[i]){
input[0] = input[i];
adjustDown(input,0,k);
}
}
int[] result = new int[k];
for(int i = 0;i<k;i++){
result[i] = input[i];
}
return result;
}
public static void buildMinHeap(int[] input, int len){
for(int i = len/2-1;i>=0;i--){
adjustDown(input,i,len);
}
}
public static void adjustDown(int[] input, int k, int len){
int temp = input[k];
for(int i = k*2+1;i<len-1;i = i*2){
if(i+1<=len-1 && input[i+1]<input[i]){
i = i+1;
}
if(input[k]<input[i]){
break;
}
input[k] = input[i];
k = i;
}
input[k] = temp;
}
}
//解法4:采用二分法,每次找到最大最小值中间的元素,看比这个元素大的元素个数是否为K,如果为K,就找比这个数大的数返回即可O(N*logN)
public class Main {
public static void main(String[] args) throws Exception {
int[] result1 = findMaxKNum1(new int[]{3,4,5,3,2,1,6,8},3);
for(int i = 0;i<result1.length;i++){
System.out.print(result1[i]+" ");
}
System.out.println();
}
public static int[] findMaxKNum1(int[] input, int k) throws Exception {
int maxValue = findMax(input);
int minValue = findMin(input);
int kValue = findKValue(input,k,minValue,maxValue);
int[] result = new int[k];
int temp = 0;
for(int i = 0;i<input.length;i++){
if(input[i]>kValue){
result[temp] = input[i];
temp++;
}
}
return result;
}
//找到数组中最大的数
public static int findMax(int[] input){
int maxValue = Integer.MIN_VALUE;
for(int i = 0;i<input.length;i++){
if(input[i]>maxValue){
maxValue = input[i];
}
}
return maxValue;
}
//找到数组中最小的数
public static int findMin(int[] input){
int minValue = Integer.MAX_VALUE;
for(int i = 0;i<input.length;i++){
if(input[i]<minValue){
minValue = input[i];
}
}
return minValue;
}
//找到排位第k大个数值
public static int findKValue(int[] input, int k, int minValue, int maxValue){
int midValue = (maxValue+minValue)/2;
int count = getCount(input, midValue);
while(count!=k){ //当比midValue大的数的个数正好等于k时就可以跳出循环,并返回midValue,即第k大的数值
if(count>k){
minValue = midValue;
}else{
maxValue = midValue;
}
midValue = (maxValue+minValue)/2;
count = getCount(input, midValue);
}
return midValue;
}
//找出数组中比num大的数的个数
public static int getCount(int[] input, int num){
int result = 0;
for(int i = 0;i<input.length;i++){
if(input[i]>num){
result++;
}
}
return result;
}
}
//解法5:类似于桶排序的方式,以空间换时间O(N)
public class Main {
public static void main(String[] args) throws Exception {
int[] result1 = findMaxKNum1(new int[]{3,4,5,3,2,1,6,8},3);
for(int i = 0;i<result1.length;i++){
System.out.print(result1[i]+" ");
}
System.out.println();
}
public static int[] findMaxKNum1(int[] input, int k) throws Exception {
int maxValue = 10;
int[] count = new int[maxValue];
for(int i = 0;i<input.length;i++){
count[input[i]]++;
}
int[] result = new int[k];
int temp = 0;
for(int i = maxValue-1;i>=0;i--){
while(count[i]>0){
count[i]--;
result[temp] = i;
temp++;
if(temp == k){ //如果数量够了就可以跳出循环
break;
}
}
if(temp == k){ //如果数量够了就可以跳出循环
break;
}
}
return result;
}
}
编程之美2.5 寻找最大的K个数
最新推荐文章于 2018-04-13 13:46:00 发布