算法导论:快速找出无序数组中第k小的数

题目描述:

给定一个无序整数数组,返回这个数组中第k小的数。

解析:

最平常的思路是将数组排序,最快的排序是快排,然后返回已排序数组的第k个数,算法时间复杂度为O(nlogn),空间复杂度为O(1)。使用快排的思想,但是每次只对patition之后的数组的一半递归,这样可以将时间复杂度将为O(n)。

在《算法导论》有详细叙述 这里主要用C++实现,实现思路就是先选取当前数组的第一个数作为“主轴”,将后面所有数字分成两部分,前面一部分小于“主轴”,后面一部分大于“主轴”,然后计算前面一部分数字的有多少,如果大于K则递归--在前面一部分找第K个数,如果小于K则在后面一部分呢找,此时K要更新一下 K需要减去第一部分数字数目,递归查找。递归的细节自己掌握以下就行,思路基本就是这样。

代码实现:

#include <iostream>
#include <string>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;

/*
题目描述:
给定一个无序整数数组,返回这个数组中第k小的数。
实现思路: 就是先选取当前数组的第一个数作为“主轴”,将后面所有数字分成两部分,前面一部分小于“主轴”,后面一部分大于“主轴”,然后计算前面一部分数字的有多少,如果大于K则递归--在前面一部分找第K个数,如果小于K则在后面一部分呢找,此时K要更新一下 K需要减去第一部分数字数目,递归查找
 */

void swap(int *p, int *q)
{
    int t;
    t = *p;
    *p = *q;
    *q = t;
}

int findNumberK(vector<int> &vec, int k, int s, int e)
// 快速排序(折半缩小递归区间的方法)查找 The K
{
    int roll = vec[s], be = 0, j = s;

    for(int i = s+1 ; i<= e ; i++)
    {
        if(vec[i] < roll)
        {
            j++;
            swap(&vec[i], &vec[j]);
            be++;
        }
    }

    swap(&vec[s], &vec[j]);

    if(be == k - 1 )
        return roll;
    else if (be < k - 1)
    {
        return findNumberK(vec, k - be - 1, j + 1, e);
    }
    else
        return findNumberK(vec, k, s, j - 1);
}

int main()
{

    vector<int> a;
    int temp, k;

    cout << "input data:" << endl;
    cin >> temp;

    while(temp != 0)
    {
        a.push_back(temp);
        cin >> temp;
    }

    cout << "input K: " << endl;
    cin >> k;

    int number = findNumberK(a , k, 0 ,a.size() - 1);
    cout << "Test Result: "  << number<< endl;
    /*
    The next use sort 模板快排进行结果验证
     */

    sort(a.begin(), a.end(), less<int>());
    cout << "real Result: "  << a[k-1] << endl;
    return 0;
}

执行结果:

时间: 2024-10-26 20:29:36

算法导论:快速找出无序数组中第k小的数的相关文章

程序员面试100题之十:快速找出一个数组中的两个数字,让这两个数字之和等于一个给定的值(转)

能否快速找出一个数组中的两个数字,让这两个数字之和等于一个给定的值,为了简化起见,我们假设这个数组中肯定存在至少一组符合要求的解. 假如有如下的两个数组,如图所示: 5,6,1,4,7,9,8 给定Sum= 10 1,5,6,7,8,9 给定Sum= 10 分析与解法 这个题目不是很难,也很容易理解.但是要得出高效率的解法,还是需要一番思考的. 解法一 一个直接的解法就是穷举:从数组中任意取出两个数字,计算两者之和是否为给定的数字. 显然其时间复杂度为N(N-1)/2即O(N^2).这个算法很简

选择问题(选择数组中第K小的数)

由排序问题可以引申出选择问题,选择问题就是选择并返回数组中第k小的数,如果把数组全部排好序,在返回第k小的数,也能正确返回,但是这无疑做了很多无用功,由上篇博客中提到的快速排序,稍稍修改下就可以以较小的时间复杂度返回正确结果. 代码如下: #include<iostream> using namespace std; #define Cutoff 3 int A[13] = {81,94,11,96,12,35,17,95,28,58,41,75,15}; void Swap(int &

求数组中第k小的数,有快速排序的验证

// The_Least_K_number.cpp : 定义控制台应用程序的入口点. //数组中第k小的数,例如a[1000]中第250小的数// #include "stdafx.h" #include <iostream> using namespace std; void swap(int *p, int *q) { int temp = *p; *p = *q; *q = temp; } int patition(int a[], int first, int la

算法题:找出一个数组中依次最大的k个元素

package arithmetic; import java.util.Arrays; /** * 找出一个数组中依次最大的k个元素 * @author SHI */ public class FindMaxFigure { public static void main(String[] args) { int[] a=new int[]{1,5,-1,8,0,2}; System.out.println(Arrays.toString(findBigFigure(a, 3))); } /*

算法题:找出整数数组中两个只出现一次的数字

问题:一个整数数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字.要求时间复杂度为O(n),空间复杂度为O(1). 分析:这是一个很新颖的关于位运算的题目. 首先考虑这个问题的一个简单版本:一个整数数组里除了一个数字之外,其他的数字都出现两次,请写程序找出这个只出现一次的数字. 这个问题的突破口在哪?题目中数组的性质是只有一个整数出现一次,其他的都出现两次.这样的话就使我们想到了异或运算的性质:任何一个数字异或它自己都等于0.也就是说如果从头到尾依次异或数组中的每

算法题:找出一个数组中相加值最大的连续序列元素

package arithmetic; /** * @author SHI * 求一个数组中相加值最大的连续序列元素 */ public class MaxSequence { public static void main(String[] args) { int[] a=new int[]{-2,9,-3,4,-6,7,-6,4}; findBigSequence(a); } /** * 思想: (1)计算出该数组的所有元素和,假设该值为最大 * (2)从数组下标1到a.length-1依次

找轮转后的有序数组中第K小的数

我们可以通过二分查找法,在log(n)的时间内找到最小数的在数组中的位置,然后通过偏移来快速定位任意第K个数. 此处假设数组中没有相同的数,原排列顺序是递增排列. 在轮转后的有序数组中查找最小数的算法如下: int findIndexOfMin(int num[],int n) { int l = 0; int r = n-1; while(l <= r) { int mid = l + (r - l) / 2; if (num[mid] > num[r]) { l = mid + 1; }

查找无序数组中第K大的数

思路: 利用快速排序的划分思想 可以找出前k大数,然后不断划分 直到找到第K大元素 代码: #include <iostream> #include <algorithm> #include <cstdio>5 using namespace std; int findK(int left, int right, int arr[], int k) { if(left >= right) return arr[left]; int first = left, la

找到轮转后的有序数组中第K小的数

我们可以通过二分查找法,在log(n)的时间内找到最小数的在数组中的位置,然后通过偏移来快速定位任意第K个数. 此处假设数组中没有相同的数,原排列顺序是递增排列. 在轮转后的有序数组中查找最小数的算法如下: int findIndexOfMin(int num[],int n) { int l = 0; int r = n-1; while(l <= r) { int mid = l + (r - l) / 2; if (num[mid] > num[size]) { l = mid + 1;