基于快速排序思想的三个算法题

一,最小的k个数

输入n个数,找出其中最小的k个数,例如输入4,5,1,6,2,7,3,8,个数字,则最小的数字是1,2,3,4

基于O(n)的算法,可以用基于Partion函数解决这个问题,如果基于数组的第k个数字来调整,使得比第k个数字小的所有数字都位于数组的左边,比第k个数组大的所有数字都位于数组的右边,这样调整之后数组左边的k个数字就是最小的k个数字,不一定有序

import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner in=new Scanner(System.in);
		int n=in.nextInt();
		int k=in.nextInt();
		int[] num=new int[n];
		int[] out=new int[k];
		for(int i=0;i<n;i++){
			num[i]=in.nextInt();
		}
	   boolean b=GetMinK(n,num,k,out);
	   if(b){
		   for(int i=0;i<k;i++){
			   System.out.print(out[i]+" ");
		   }
	   }

	}
	public static boolean GetMinK(int uiInputNum, int[] pInputArray, int uiK, int[] pOutputArray){
		  if(pInputArray==null||pOutputArray==null||uiK>uiInputNum||uiInputNum<=0||uiK<=0){
			 return false;
		  }
		  int start=0;
		  int end=uiInputNum-1;
		  int index=partition(pInputArray,start,end);
		  while(index!=uiK-1){
			    if(index>uiK-1){//index在k-1的右边
			    	 end=index-1;
			    	 index=partition(pInputArray,start,end);
			    }
			    else{
			    	start=index+1;
			    	index=partition(pInputArray,start,end);
			    }
		  }
		  for(int i=0;i<uiK;i++){
			  pOutputArray[i]=pInputArray[i];
		  }
		  return true;

	}
	//partion分区函数,返回数组a的首元素快排的索引值index
	public static int partition(int[] a,int start,int end){
		  int privot=a[start];
		  int i=start;
		  int j=end;
		  while(i<j){
			  while(i<j&&privot<=a[j]){
				  j--;
			  }
			  swap(a,i,j);
			  while(i<j&&privot>=a[i]){
				  i++;
			  }
			  swap(a,i,j);
		  }
		  return i;

	}
	public static void swap(int[] a,int i,int j){
		int t=a[i];
		a[i]=a[j];
		a[j]=t;
	}
}

二,数组中出现次数超过一半的数字

数组中有一个数字出现次数超过数组长度的一半,请找出这个数字。例如1,2,3,2,2,2,5,4,2,数字2在数组中出现了5次,超过数组长度的一半,输出2

受快速排序的启发,在快速排序中,现在数组中选择一个数字,然后调整数组中的数字的顺序,使得比选中数字小的数字都排在它的左边,比选中数字大的数字都排在它的右边。

如果选中的数字的下标刚好是n/2,那么这个数字就是数组中的中位数

import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner in=new Scanner(System.in);
		int n=in.nextInt();

		int[] num=new int[n];

		for(int i=0;i<n;i++){
			num[i]=in.nextInt();
		}
	   int b=GetHalfNum(n,num);
	   if(b!=-1){
		  System.out.println(b);
	   }

	}
	public static int GetHalfNum(int uiInputNum, int[] pInputArray){
		  if(pInputArray==null||uiInputNum<=0){
			 return -1;
		  }
		  int middle=uiInputNum>>1;//长度的一半
		  int start=0;
		  int end=uiInputNum-1;
		  int index=partition(pInputArray,start,end);
		  while(index!=middle){//如果不等于长度的一半说明就没有找到这个中位数
			    if(index>middle){
			    	 end=index-1;
			    	 index=partition(pInputArray,start,end);
			    }
			    else{
			    	start=index+1;
			    	index=partition(pInputArray,start,end);
			    }
		  }

		  return pInputArray[index];//index=middle

	}

	public static int partition(int[] a,int start,int end){
		  int privot=a[start];
		  int i=start;
		  int j=end;
		  while(i<j){
			  while(i<j&&privot<=a[j]){
				  j--;
			  }
			  swap(a,i,j);
			  while(i<j&&privot>=a[i]){
				  i++;
			  }
			  swap(a,i,j);
		  }
		  return i;

	}
	public static void swap(int[] a,int i,int j){
		int t=a[i];
		a[i]=a[j];
		a[j]=t;
	}
}

三,找出数组中第k个最小的数

例如给定数组1,5,2,6,8,0,6中,第4小的数字是5

import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner in=new Scanner(System.in);
		int n=in.nextInt();
		int k=in.nextInt();
		int[] num=new int[n];
		//int[] out=new int[k];
		for(int i=0;i<n;i++){
			num[i]=in.nextInt();
		}
	   int b=GetMinK(n,num,k);
	   if(b!=-1){
		  System.out.println(b);
	   }

	}
	public static int GetMinK(int uiInputNum, int[] pInputArray, int uiK){
		  if(pInputArray==null||uiK>uiInputNum||uiInputNum<=0||uiK<=0){
			 return -1;
		  }
		  int start=0;
		  int end=uiInputNum-1;
		  int index=partition(pInputArray,start,end);
		  while(index!=uiK-1){//如果index不是k-1的位置
			    if(index>uiK-1){
			    	 end=index-1;
			    	 index=partition(pInputArray,start,end);
			    }
			    else{
			    	start=index+1;
			    	index=partition(pInputArray,start,end);
			    }
		  }

		  return pInputArray[index];//返回的这个位置的数值

	}

	public static int partition(int[] a,int start,int end){
		  int privot=a[start];
		  int i=start;
		  int j=end;
		  while(i<j){
			  while(i<j&&privot<=a[j]){
				  j--;
			  }
			  swap(a,i,j);
			  while(i<j&&privot>=a[i]){
				  i++;
			  }
			  swap(a,i,j);
		  }
		  return i;

	}
	public static void swap(int[] a,int i,int j){
		int t=a[i];
		a[i]=a[j];
		a[j]=t;
	}
}
时间: 2024-08-02 14:07:13

基于快速排序思想的三个算法题的相关文章

基于快速排序的查找前K个最大数

快速排序 下面是之前实现过的快速排序的代码. function quickSort(a,left,right){ if(left<right){ let mid=partition(a,left,right);//选出key下标 quickSort(a,left,mid-1);//对key的左半部分排序 quickSort(a,mid+1,right)//对key的右半部份排序 } } function partition(a,left,right){ let key=a[left];//一开始

笔试算法题(54):快速排序实现之单向扫描、双向扫描(single-direction scanning, bidirectional scanning of Quick Sort)

议题:快速排序实现之一(单向遍历) 分析: 算法原理:主要由两部分组成,一部分是递归部分QuickSort,它将调用partition进行划分,并取得划分元素P,然后分别对P之前的部分和P 之后的部分递归调用QuickSort:另一部分是partition,选取划分元素P(随机选取数组中的一个元素,交换到数组末尾位置),定义两个标记 值left和right,随着划分的进行,这两个标记值将数组分成三部分,left之左的部分是小于划分元素P的值,left和right之间的部分是大 于等于划分元素P的

笔试算法题(54):快速排序实现之三路划分, 三元中值法和插入排序处理小子文件

议题:快速排序算法实现之三(三路划分遍历,解决与划分元素相等元素的问题) 分析: 算法原理:使用三路划分策略对数组进行划分(也就是荷兰国旗问题,dutch national flag problem).这个实现是对实现二的改进,它添加处理等于划分元素的值的逻辑,将所有等于划分元素的值集中在一起,并且以后都不会再对他们进行划分. 本算法中使用四个标示值进行操作.使用left和right同时向中间遍历时,当left遇见等于划分元素时,就与iflag指向的值进行交换 (iflag指向的当前值到最左端表

笔试算法题(55):快速排序实现之非递归实现,最小k值选择(non-recursive version, Minimal Kth Selection of Quick Sort)

议题:快速排序实现之五(非递归实现,短序列优先处理,减少递归栈大小) 分析: 算法原理:此算法实现适用于系统栈空间不足够快速排序递归调用的需求,从而使用非递归实现快速排序算法:使用显示下推栈存储快速排序中的每一次划分结果 (将left和right都压入堆栈),并且首先处理划分序列较短的子序列(也就是在得到一次划分的左右部分时,首先将长序列入栈,然后让段序列入栈), 这样可以保证当快速排序退化的线性效率的时候,栈大小仍旧在㏒N范围内.算法策略类似于最小子树优先遍历规则: 弱势:当序列已经就绪,每次

经典算法题每日演练——第三题 猴子吃桃

原文:经典算法题每日演练--第三题 猴子吃桃 猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾就多吃了一个.第二天早上又将剩下的桃子吃了一半,还是不过瘾又多 吃了一个.以后每天都吃前一天剩下的一半再加一个.到第10天刚好剩一个.问猴子第一天摘了多少个桃子? 分析: 这是一套非常经典的算法题,这个题目体现了算法思想中的递推思想,递归有两种形式,顺推和逆推,针对递推,只要 我们找到递推公式,问题就迎刃而解了. 令S10=1,容易看出 S9=2(S10+1), 简化一下 S9=2S10+2 S8=2S

LeetCode算法题-First Bad Version(Java实现-三种解法)

这是悦乐书的第200次更新,第210篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第66题(顺位题号是278).您是产品经理,目前领导团队开发新产品.不幸的是,您产品的最新版本未通过质量检查.由于每个版本都是基于以前的版本开发的,因此坏版本之后的所有版本也是坏的. 假设您有n个版本[1,2,...,n]并且您想找出第一个坏的版本,这会导致以下所有版本都不好.您将获得一个API bool isBadVersion(版本),它将返回版本是否错误. 实现一个函数来查找第一

快速排序、归并排序、堆排序三种算法性能比较

快速排序.归并排序.堆排序三种排序算法的性能谁最好呢?网上查了一下说快速排序最快.其次是归并排序,最差的是堆排序:而理论上三种排序算法的时间复杂度都是O(nlogn),只不过快速排序最差的会达到O(n^2),但是数据的随机性会消除这一影响,今天就来实际比较一下: 1 #include <iostream> 2 #include<time.h> 3 using namespace std; 4 #define MAX 100000000 5 int data1[MAX],data2[

每天刷个算法题20160525:快速排序的递归转非递归解法

版权所有.所有权利保留. 欢迎转载,转载时请注明出处: http://blog.csdn.net/xiaofei_it/article/details/51524798 为了防止思维僵化,每天刷个算法题.已经刷了几天了,现在发点代码. 我已经建了一个开源项目,每天的题目都在里面: https://github.com/Xiaofei-it/Algorithms 绝大部分算法都是我自己写的,没有参考网上通用代码.读者可能会觉得有的代码晦涩难懂,因为那是我自己的理解. 最近几天都是在写一些原来的东西

C++笔试面试(算法题集三)

1>    编写strcpy函数,已知函数原型char*strcpy(char* strDest,char* strSrc) ANSWER: Chat* strcpy(char* strDest,char* strSrc) { If(strSrc==NULL)  return NULL; Char*ch1=strSrc,*ch2=strDest; While(*ch1!='\0') { *ch2++=*ch1++; } *ch2='\0'; Return strDest; } 2>    用递