求两个排序数组的第K大元素--求全排列的第K大元素
2014-06-29 22:19
357 查看
2.1.5 求两个排序数组的第K大元素。
很多人首先想到的是merge,时间复杂度O(m+n).有没有更快的办法。O(log k)
我们可以考虑从k入手。如果我们每次都能够删除一个一定在第k大元
素之前的元素,那么我们需要进行k次。但是如果每次我们都删除一半呢?由于A和B都是有序
的,我们应该充分利用这里面的信息,类似于二分查找,也是充分利用了“有序”。
假设A和B的元素个数都大于k/2,我们将A的第k/2个元素(即A[k/2-1])和B的第k/2
个元素(即B[k/2-1])进行比较,有以下三种情况(为了简化这里先假设k为偶数,所得到的结
论对于k是奇数也是成立的):
A[k/2-1] == B[k/2-1]
A[k/2-1] > B[k/2-1]
A[k/2-1] < B[k/2-1]
如果A[k/2-1] < B[k/2-1],意味着A[0]到A[k/2-1]的肯定在A[B的top k元素的范围
内,换句话说,A[k/2-1不可能大于A[B的第k大元素。留给读者证明。
因此,我们可以放心的删除A数组的这k/2个元素。同理,当A[k/2-1] > B[k/2-1]时,可
以删除B数组的k/2个元素。
当A[k/2-1] == B[k/2-1]时,说明找到了第k大的元素,直接返回A[k/2-1]或B[k/2-1]
即可。
因此,我们可以写一个递归函数。那么函数什么时候应该终止呢?
当A或B是空时,直接返回B[k-1]或A[k-1];
当k=1是,返回min(A[0], B[0]);
当A[k/2-1] == B[k/2-1]时,返回A[k/2-1]或B[k/2-1]
求全排列的第K大元素。例如:123全排列。第五大元素是312.
笨方法:枚举+排序
巧妙方法:康托展开。
X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0! 其中,a为整数,并且0<=ai<i(1<=i<=n)。这就是康托展开
假设有n个不重复的元素,第k个排列是a1; a2; a3; :::; an,那么a1是哪一个位置呢?
我们把a1去掉,那么剩下的排列为a2; a3; :::; an, 共计n-1个元素,n-1个元素共有(n-1)!个排列,于是就可以知道a1 =k/(n-1)!。
同理,a2; a3; :::; an的值推导如下:
k2 = k%(n-1)!
a2 = k2/(n 2)!
::: = :::
kn-1 = kn-2%2!
an-1 = kn-1/1!
an = 0
例1 {1,2,3,4,5}的全排列,并且已经从小到大排序完毕
(1)找出第96个数
首先用96-1得到95 //下标从0开始,12345本身是第一个
用95去除4! 得到3余23
有3个数比它小的数是4
所以第一位是4
用23去除3! 得到3余5
有3个数比它小的数是4但4已经在之前出现过了所以第二位是5(4在之前出现过,所以实际比5小的数是3个)
用5去除2!得到2余1
有2个数比它小的数是3,第三位是3
用1去除1!得到1余0
有1个数比它小的数是2,第二位是2
最后一个数只能是1
所以这个数是45321
注意:如果是不连续的全排列,1,3,5,6的全排列。上题第一步的得到3余23,里面的3是指索引3. 另vector list=(1,3,5,6)。a1=list[3],就是6,然后用完之后要切记erase掉,因为一个元素的排序只出现一次,因为有时候会遇到a2=0,a3=0的情况,123全排列的第5大元素,a1=(5-1)/4!=2, k=4%2=0; a2=0/1!=0, a3=0/0!=0; 所以a1=list[2]=3,(删除 list[2])
a2=list[0]=1,(删除list[0]), 后a3=list[0]=2(如果不删除就是1,结果就是311);
fg
很多人首先想到的是merge,时间复杂度O(m+n).有没有更快的办法。O(log k)
我们可以考虑从k入手。如果我们每次都能够删除一个一定在第k大元
素之前的元素,那么我们需要进行k次。但是如果每次我们都删除一半呢?由于A和B都是有序
的,我们应该充分利用这里面的信息,类似于二分查找,也是充分利用了“有序”。
假设A和B的元素个数都大于k/2,我们将A的第k/2个元素(即A[k/2-1])和B的第k/2
个元素(即B[k/2-1])进行比较,有以下三种情况(为了简化这里先假设k为偶数,所得到的结
论对于k是奇数也是成立的):
A[k/2-1] == B[k/2-1]
A[k/2-1] > B[k/2-1]
A[k/2-1] < B[k/2-1]
如果A[k/2-1] < B[k/2-1],意味着A[0]到A[k/2-1]的肯定在A[B的top k元素的范围
内,换句话说,A[k/2-1不可能大于A[B的第k大元素。留给读者证明。
因此,我们可以放心的删除A数组的这k/2个元素。同理,当A[k/2-1] > B[k/2-1]时,可
以删除B数组的k/2个元素。
当A[k/2-1] == B[k/2-1]时,说明找到了第k大的元素,直接返回A[k/2-1]或B[k/2-1]
即可。
因此,我们可以写一个递归函数。那么函数什么时候应该终止呢?
当A或B是空时,直接返回B[k-1]或A[k-1];
当k=1是,返回min(A[0], B[0]);
当A[k/2-1] == B[k/2-1]时,返回A[k/2-1]或B[k/2-1]
double find_kth(int A[], int m, int B[], int n, int k) { //always assume that m is equal or smaller than n if (m > n) return find_kth(B, n, A, m, k); if (m == 0) return B[k - 1]; if (k == 1) return min(A[0], B[0]); //divide k into two parts int pa = min(k / 2, m), pb = k - pa; if (A[pa - 1] < B[pb - 1]) return find_kth(A + pa, m - pa, B, n, k - pa); else if (A[pa - 1] > B[pb - 1]) return find_kth(A, m, B + pb, n - pb, k - pb); else return A[pa - 1]; }2.1.12
求全排列的第K大元素。例如:123全排列。第五大元素是312.
笨方法:枚举+排序
巧妙方法:康托展开。
X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0! 其中,a为整数,并且0<=ai<i(1<=i<=n)。这就是康托展开
假设有n个不重复的元素,第k个排列是a1; a2; a3; :::; an,那么a1是哪一个位置呢?
我们把a1去掉,那么剩下的排列为a2; a3; :::; an, 共计n-1个元素,n-1个元素共有(n-1)!个排列,于是就可以知道a1 =k/(n-1)!。
同理,a2; a3; :::; an的值推导如下:
k2 = k%(n-1)!
a2 = k2/(n 2)!
::: = :::
kn-1 = kn-2%2!
an-1 = kn-1/1!
an = 0
例1 {1,2,3,4,5}的全排列,并且已经从小到大排序完毕
(1)找出第96个数
首先用96-1得到95 //下标从0开始,12345本身是第一个
用95去除4! 得到3余23
有3个数比它小的数是4
所以第一位是4
用23去除3! 得到3余5
有3个数比它小的数是4但4已经在之前出现过了所以第二位是5(4在之前出现过,所以实际比5小的数是3个)
用5去除2!得到2余1
有2个数比它小的数是3,第三位是3
用1去除1!得到1余0
有1个数比它小的数是2,第二位是2
最后一个数只能是1
所以这个数是45321
注意:如果是不连续的全排列,1,3,5,6的全排列。上题第一步的得到3余23,里面的3是指索引3. 另vector list=(1,3,5,6)。a1=list[3],就是6,然后用完之后要切记erase掉,因为一个元素的排序只出现一次,因为有时候会遇到a2=0,a3=0的情况,123全排列的第5大元素,a1=(5-1)/4!=2, k=4%2=0; a2=0/1!=0, a3=0/0!=0; 所以a1=list[2]=3,(删除 list[2])
a2=list[0]=1,(删除list[0]), 后a3=list[0]=2(如果不删除就是1,结果就是311);
template<typename Sequence> Sequence kth_permutation(const Sequence &seq, int k) { const int n = seq.size(); Sequence S(seq); Sequence result; int base = factorial(n - 1); --k; // 康托编码从0 开始 for (int i = n - 1; i > 0; k %= base, base /= i, --i) { auto pos = next(S.begin(), k / base); result.push_back(*pos); S.erase(pos); } result.push_back(S[0]); // 最后一个 return result; }</span>
fg
相关文章推荐
- 两个排序的数组,找到第k大的元素
- 【转载】两个排序数组的中位数 / 第K大元素(Median of Two Sorted Arrays)
- 求两个已排序的数组中所有元素的第K大(小)
- LeetCode--找到两个排序数组中第k大的元素
- 面试算法:lg(k)时间查找两个排序数组合并后第k小的元素
- 在两个排序数组中查找第k小元素
- 在2个排序数组内找到第K小的元素
- 找出两个数组中相同的元素,不排序直接两次循环取出
- 两个排序数组取第k小的数字
- 面试题之陈利人 两个数组中求第k小元素
- 求两个有序数组的中位数和者第k小元素
- 两个排序数组合并第k或前k个最小值问题
- 查找两个已经排好序的数组的第k大的元素
- 编写一个程序,输入两个包含 5 个元素的数组,先将两个数组升序排序,然 后将这两个数组合并成一个升序数组(合并排序)。
- 在排序数组中查找和为定值的两个元素
- 求两个有序数组的中位数和者第k小元素
- 查找两个已经排好序的数组的第k大的元素
- 找包含N个元素的数组里第K大的元素(引申:快速排序、找中位数、找前K大的元素)的时间复杂度
- 两个数组[n] [m] n>m 第一个数组的数字无序排列 第二个数组为空 取出第一个数组的最小值 放到第二个数组中第一个位置, 依次类推. 不能改变A数组,不能对之进行排序,也不可以倒到别的数组中。
- 两个数组 [n] [m] n>m 第一个数组的数字无序排列 第二个数组为空 取出第一个数组的最小值 放到第二个数组中第一个位置, 依次类推. 不能改变A数组,不能对之进行排序,也不可以倒到别的数组中。