学习笔记,可能有些谬误,请批判性阅读。
k个有序列表的全局排序。
思路1:两两归并,直至第k个
思路2:建立大小为k的最小堆,进行归并。
求数组的逆序对
参考[1],实际就是归并排序,在归并排序的过程中,如果有逆序对出现,进行累加,累加值为右子序列的剩余长度。需要注意的是,从后往前归并。
哎,我那脑袋不好使的时候写不出来的归并排序啊。
void merge(int* a, int* b, int l, int m, int r, int& reverse_count){
// a是原始数组,a[l...m],a[m+1...r]分别是左右两个子序列
// b是个辅助数组,用来暂存排归并后的序列。
// reverse_count用来存储逆序对数目
// 因为比较逆序,左边的数大于右边的数视为一个逆序。
// 因此从后往前遍历
int i = m;
int j = r;
int k = r;
while(k >= 0){
if(i < l){ // 左子序列遍历完成
b[k--] = a[j--];
}else if(j < m + 1){ // 右子序列遍历完成
b[k--] = a[i--];
}else{
if(a[i] > a[j]){ // 取较大值放入b,另外,此时构成了逆序
b[k--] = a[i--];
reverse_count += j - m; // 右子序列剩余多少个元素,就有多少个逆序对。
}else{
b[k--] = a[j--];// 若a[i] <= b[j],不构成逆序
}
}
}
for(k = l; k <= r; k++){
a[k] = b[k];
}
}
void merge_sort_helper(int* a, int* b, int l, int r, int& reverse_count){
if(l >= r){
return;
}
mid = (l + r) / 2;
merge_sort_helper(a, b, l, mid, reverse_count);
merge_sort_helper(a, b, mid + 1, r, reverse_count);
merge(a, b, l, mid, r, reverse_count);
}
int merge_sort(int* a, int n){
if(n<=1){
return
}
int* b = new int[n];
int reverse_count = 0;
merge_sort_helper(a, b, 0, n - 1, reverse_count);
delete b;
return reverse_count;
}
与问题|排序一文中的归并排序基本是一致的,除了细节处为了记录逆序对数做的添加。
又及,这里涉及到引用,可以参考[3] & [4]。
求数组中第k大的数
求数组中前k大的数
求数组中出现次数超过一半的数
参考[2],第二种思路是快排,出现超过一半的数,第n/2大的数一定是这个数,就和「求数组中前k大的数」成了一样的问题。
第一种思路比较牛批。
遍历数组是保存两个值:
一个是数字中的一个数字,另一个是次数。
当遍历到下一个数字的时候,如果下一个数字和之前保存的数字相等,则次数加1;
如果不同,则次数减1;如果次数为零,那么我们需要保存下一个数字,并把次数设置为1。
由于我们要找的数字出现的次数比其他所有数字出现的次数之和还要多,
那么要找的数字肯定是最后一次把次数设置为1时对应的数字。
求数组中的最大值和最小值
《编程之美》上的问题。依靠分治思想。
参考
[1] https://blog.csdn.net/qq_28081081/article/details/80804781
[2] https://blog.csdn.net/SCS199411/article/details/91462505
[3] https://www.runoob.com/cplusplus/cpp-references.html
[4] https://www.runoob.com/cplusplus/passing-parameters-by-references.html
网友评论