MIT-寻找第k小的元素
文章目录
- 问题描述
- 例子
- 算法实现
- 暴力算法
- 分治算法(快排思想)
问题描述
给定一个包含 nnn 个互不相同整数的数组 A[n]A[n]A[n],以及一个正整数 kkk,请你找出数组 AAA 中第 kkk 小的元素。
例子
输入
A = [7, 10, 4, 3, 20, 15]
k = 3输出
7
算法实现
暴力算法
寻找第 kkk 小的元素最直接的方法是对所有的元素排序,然后取出数组 AAA 中第 kkk 个元素(A[k]A[k]A[k])。
int bruteSearchKth(int &A[], int k, int n)
{quickSort(A, 0, n - 1);return A[k - 1];
}
时间复杂度:O(nlog2n)O(n\log_2 n)O(nlog2n)
分治算法(快排思想)
MIT-归并排序和快速排序:参考这篇文章的 partition 函数。
int partition(int &A[], int low, int high)
{int i = low - 1, j = low;int x = A[high];while (j <= high - 1){if (A[j] < x) swap(A[ ++ i], A[j]);j ++ ;}swap(A[i + 1], A[high]);return i + 1;
}
我们记 partition 函数返回的值是 qqq,即表示第 qqq 小的数 A[q]A[q]A[q],那么:
- 若 k<qk<qk<q,则我们要找的结果就是在 [low,q−1][low, q-1][low,q−1]
- 若 k>qk>qk>q,则我们要找的结果就是在 [q+1,high][q+1, high][q+1,high]
- 若 k=qk=qk=q,则 qqq 正是我们要找的那个值。
int DCSearchKth(int &A[], int k, int low, int high)
{int q = partition(A, low, high);if (q == k - 1) return A[q];else if (k - 1 < q) return DCSearchKth(A, k, low, q - 1);else (k > q) return DCSearchKth(A, k, q + 1, high);
}
时间复杂度:O(n)O(n)O(n)
假设 n=2hn=2^hn=2h 且 T(1)=O(1)T(1)=O(1)T(1)=O(1),T(n)T(n)T(n) 是执行一次大小为 nnn 次的 DCSearchKth 所需的时间。(假设每次都只进入分区的一半)
DCSearchKth(A, low, q - 1)或DCSearchKth(A, q + 1, high):T(n2)T(\frac{n}{2})T(2n)quickSort(A, mid + 1, high):T(n2)T(\frac{n}{2})T(2n)int q = partition(A, low, high):O(n)O(n)O(n)
T(n)=T(n2)+O(n)≤T(n2)+cn≤T(n22)+cn(1+12)≤...≤T(n2h)+cn[(12)0+(12)1+(12)2+...+(12)h−1]=T(1)+2cn(2−h−1)=T(1)+2cn(1n−1)≤O(1)+2cn=O(n)\begin{aligned} T(n)&=T(\frac{n}{2})+O(n) \\&\leq T(\frac{n}{2})+cn \\&\leq T(\frac{n}{2^2})+cn(1+\frac{1}{2}) \\&\leq ... \\&\leq T(\frac{n}{2^h})+cn\left[(\frac{1}{2})^0+(\frac{1}{2})^1+(\frac{1}{2})^2+...+(\frac{1}{2})^{h-1}\right] \\&= T(1)+2cn(2^{-h}-1) \\&=T(1)+2cn(\frac{1}{n}-1) \\&\leq O(1)+2cn \\&=O(n) \end{aligned}T(n)=T(2n)+O(n)≤T(2n)+cn≤T(22n)+cn(1+21)≤...≤T(2hn)+cn[(21)0+(21)1+(21)2+...+(21)h−1]=T(1)+2cn(2−h−1)=T(1)+2cn(n1−1)≤O(1)+2cn=O(n)
