1、输入n个整数,输出其中最小的k个。
思路1:先快速排序,然后取前k个数。时间复杂度:O(n * log n)+O(k)=O(n * log n)。
思路2:a)定义一个长度为k的数组result,将前k个整数放入result;
b)采用选择或交换排序找到result数组的最大值max;
c)依次遍历后n-k个整数,若其>max,说明其不是最小k个数之一并跳过,若其<max,则使max = 该数,并重复b)过程。
这种算法最差情况下的时间复杂度:O(k)+(n-k)*O(k)=O(n*k)
思路3:a)选择一个数pivot将数组分成两部分Sa和Sb,使得Sa的元素都小于等于pivot,Sb的元素都大于pivot;
b)如果k<Sa元素个数,则返回Sa中较小最小的k个元素,即递归Sa;
c)如果k=Sa元素个数,则Sa中元素就是最小的k个元素,
d)如果k>Sa元素个数,则返回Sa中所有元素和Sb中(k-|Sa|)个元素,即递归Sb。
这种平均时间复杂度:O(n*logk),二分法!
思路1代码如下:
<span style="font-size:14px;">public class CodeFour{
public static void main(String[] args){
int[] num = new int[]{1,5,5,6,8,10,131,2,1,3};
mySort(num,0,num.length-1);
int k = 3;
for(int i=0;i<k;i++){
System.out.print(num[i]+" ");
}
}
public static void mySort(int[] arr,int left, int right){
if(right-left<=1){
if(arr[left]>arr[right])
swap(arr,left,right);
return;
}
int i = left;
int j = right;
int pivot = arr[i];
while(left<right){
while(arr[right]>pivot&&left<right){
right--;
}
while(arr[left]<=pivot&&left<right){
left++;
}
if(left<right)
swap(arr,left,right);
}
swap(arr,i,right);
if(i<right-1)
mySort(arr,i,right-1);
if(right+1<j)
mySort(arr,right+1,j);
}
public static void swap(int[] arr, int index1, int index2){
int temp = arr[index1];
arr[index1] = arr[index2];
arr[index2] = temp;
}
}</span>
思路2代码如下:
<span style="font-size:14px;">public class CodeThree{
public static void main(String[] args){
int[] arr = new int[]{1,5,5,6,8,10,131,2,1,3};
int k = 3;
minK(arr,k);
}
public static void minK(int[] arr, int k){
int[] result = new int[k];
for(int i=0;i<k;i++){
result[i] = arr[i];
}
findMax(result,k);
for(int i=k;i<arr.length;i++){
if(arr[i]<result[0]){
result[0] = arr[i];
findMax(result,k);
}
}
for(int i=0;i<k;i++){
System.out.print(result[i]+" ");
}
}
public static void findMax(int[] arr, int len){
for(int i=1;i<len;i++){
if(arr[i]>arr[0])
swap(arr,i,0);
}
}
public static void swap(int[] arr, int index1, int index2){
int temp = arr[index1];
arr[index1] = arr[index2];
arr[index2] = temp;
}
}
</span>
思路3代码如下:
<span style="font-size:14px;">public class CodeOne{
public static void main(String[] args){
int[] arr = new int[]{5,4,3,2,1};
int k = 3;
minK2(arr,0,arr.length-1,k);
}
public static void minK2(int[] arr, int left, int right,int k){
int pivot = arr[left];
int i = left;
int j = right;
while(i<j){
while(arr[j]>pivot&&i<j){
j--;
}
while(arr[i]<=pivot&&i<j){
i++;
}
if(i<j)
swap(arr,i,j);
}
swap(arr,left,j);
if(i-left+1==k){
for(int c=left;c<=i;c++)
System.out.println(arr[c]);
return;
}if(i-left+1>k){
minK2(arr,left,i,k);
}if(i-left+1<k){
for(int c=left;c<=i;c++)
System.out.println(arr[c]);
minK2(arr,i+1,right,k-(i-left+1));
}
}
public static void swap(int[] arr, int index1, int index2){
int temp = arr[index1];
arr[index1] = arr[index2];
arr[index2] = temp;
}
}
</span>
2、两个升序序列A=(a1,...,ak)和B=(b1,...,bk),求k个最小的(ai+bj),其中1<i, j<n
思路1:两个数组相加得到k*k个数,转变成求新数组的k个最小值的问题;
时间复杂度:O(k*k)+(k*k)*O(k)=O(k*k*k)
思路2:a)找到最小的整数n,满足n*(n+1)/2>=k;
b)若n*(n+1)/2=k,则满足 i+j<=n 的n*(n+1)/2个数(arr1[i]+arr2[j])即为所求,输出结果程序结束;
c)若n*(n+1)/2>k,则满足 i+j<=n-1 的(n-1)*n/2个数属于所求,另外(k-(n-1)*n/2)个结果在满足 i+j=n 的n个数中;
d)求满足 i+j=n 的n个数中最小的(k-(n-1)*n/2)个数,即上文题1。
采用快速排序方法下的时间复杂度:O(sqrt(k))+O(sqrt(k) * logsqrt(k))= O(sqrt(k)* log sqrt(k))
对上述算法解释一下,因为自己想到的,好得意,啊哈哈~欢迎打脸~~~
A、B两个数组中数两两相加可得k*k个数,形成一个新的二维数组 C[i, j] = A[i] + B[j],要求的就是数组 C 中的k个最小值。因为数组A、B是升序序列,则一定有C[i, j]<=C[m, n],其中m+n>i+j。
以A={1,2,3,4,5}、B={3,4,5,6,7}为例,k=5,满足n*(n+1)/2>=k的最小正整数为n=3,则最小的k个数一定在i+j<n(i,j从0开始)中。
从上图可以看出,在不计算数组C中元素值的情况下,仅凭索引号可知越靠近左上角值越小,处于同一45°直线上(图中以同一颜色标出)元素之间的大小必须通过计算才能得知。k个最小数也都在左上角,k=5,n=3,则属于 i+j<n-1 范围内的(n-1)*n/2个数一定属于k个最小数,剩下的数都在满足i+j = n-1的直线上,因此仅需要对该直线上的元素判断即可。
思路2代码如下:
public static void myfun(int[] arr1, int[] arr2, int k){
int n=1;
while(n*(n+1)/2<k){
n++;
}
for(int i=0;i<n-1;i++)
for(int j=0;j<n-i-1;j++)
System.out.println((arr1[i]+arr2[j]));
if(n*(n+1)/2==k){
for(int i=0;i<n;i++)
System.out.println((arr1[i]+arr2[n-i-1]));
}else{
//满足i+j=n-1的数共有n个,找出这n个数中前(k-(n-1)*n/2)个最小值即可
int[] num = new int[n];
for(int i=0;i<n;i++){
num[i]=arr1[i]+arr2[n-i-1];
}
minK(num, k-(n-1)*n/2);
}
}
其他思路:最小堆(http://www.lxway.com/285890664.htm)、辅助数组(http://blog.csdn.net/sunnianzhong/article/details/8932374)