单峰数组求第k大算法

本文介绍了一种高效算法,用于在单峰数组中寻找第k大的元素。通过对比两个有序数组的第k/2个元素,可以快速排除一半的候选元素,最终达到O(logk)的时间复杂度。文章提供了详细的算法解释和C++实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

单峰数组实际上可以看成两个有序的数组,这个问题就转变成了两个有序数组求第k大。

容易想到的算法是对这两个数组进行归并,生成一个新的有序数组,求出第k大之后就可以立刻停止,复杂度是O(k)的。

但是还有更优的算法,可以使用分治的思想(实际上也是一种二分)来计算。

对于两个有序的数组a和b,取出他们第k/2个元素进行比较,这种时候就会产生大于、小于和等于三种情况,对于这三种情况:

1、a的取出元素大于b的取出元素
说明b中的前k/2个元素全部小于a的第k/2个元素,第k大一定不在b的前k/2个中,因此这一部分可以全部丢掉,到剩下的部分中去找第k - k/2大。

2、小于的情况,和1刚好相反,丢弃a的前k/2个,去找剩下的k - k/2。

3、相等的情况。
相等的情况比较复杂,如果k是偶数,那么此刻就已经获得了第k大(a数组k/2个,b数组k/2个,加起来刚好k个),直接返回即可,奇数则需要比较a、b数组的下一个数,返回小的那个。
但是这样讨论比较挫,相等的情况实际上可以被包含在上面两种情况的代码里处理掉,除非空间和时间要求特别大,可以忽略掉。

然后就是某个数组出现了不足以取k/2个的情况,那么很显然,第k大不在这个数组里,可以直接减掉这一部分,去另外一个数组找。

到了最后,k等于1时,就找到了第k大,返回两个数组当前位置的最小值即可。

这样的算法用循环实现起来真的是难写,但是用递归写起来就很舒服了,确定好两个起始位置之后一直往下递归就完事了。

代码:

#include<bits/stdc++.h>
using namespace std;

const int maxn = 1e5 + 5;
const int inf = 1e9 + 7;

int a[maxn], b[maxn], mid, n;


int kth(int s1, int s2, int k) {

	if(s1 >= mid) {
		return b[s2 + k - 1];
	}

	if(s2 >= n - mid) {
		return a[s1 + k - 1];
	}

	if(k == 1) {
		return min(a[s1], b[s2]);
	}

	int end1 = inf, end2 = inf;
	if(s1 + k / 2 - 1 < mid) {
		end1 = a[s1 + k / 2 - 1];
	}
	if(s2 + k / 2 - 1 < n - mid) {
		end2 = b[s2 + k / 2 - 1];
	}
	if(end1 < end2) {
		return kth(s1 + k / 2, s2, k - k / 2);
	}
	return kth(s1, s2 + k / 2, k - k / 2);
}

/*
8
1 2 4 8 7 3 3 2
*/

int main() {
	int k;
	cin >> n;

	mid = n / 2;

	for(int i = 0; i < mid; i++) {
		cin >> a[i];
	}

	for(int i = 0; i < n - mid; i++) {
		cin >> b[n - mid - i - 1];
	}
	
	while(cin >> k) {
		cout << kth(0, 0, k) << endl;
	}

	return 0;
}
### 南京邮电大学算法课程相关课后习题与资料 在南京邮电大学的算法课程中,常见的课后习题涉及多个主题,包括但不限于矩阵运算、搜索算法以及编程实践等内容。以下是针对这些主题的具体描述: #### 1. 矩阵连乘问题优化 矩阵连乘问题是计算机科学中的经典动态规划问题之一,在数学和工程领域具有广泛应用。该问题的核心在于利用矩阵乘法的结合律特性来减少不必要的标量乘法次数,从而提升计算效率[^1]。 ```python def matrix_chain_order(p): n = len(p) - 1 m = [[0 for _ in range(n)] for _ in range(n)] s = [[0 for _ in range(n)] for _ in range(n)] for l in range(2, n + 1): for i in range(1, n - l + 2): j = i + l - 1 m[i-1][j-1] = float('inf') for k in range(i, j): q = m[i-1][k-1] + m[k][j-1] + p[i-1]*p[k]*p[j] if q < m[i-1][j-1]: m[i-1][j-1] = q s[i-1][j-1] = k return m, s ``` 上述代码实现了动态规划方法解决矩阵链乘问题的过程,能够有效降低时间复杂度至 \(O(n^3)\)。 --- #### 2. 学生结构体数据处理 对于学生信息管理类题目,通常会涉及到结构化数据的操作。例如,《MATLAB数学实验》第三版提供了关于如何随机生成一组学生的成绩并进行统计分析的例子[^2]。下面是一个类似的 Python 实现版本: ```python import random class Student: def __init__(self, name, id_num, grades): self.name = name self.id = id_num self.grades = grades students = [] m = random.randint(30, 60) for i in range(m): student_name = f'Student {i+1}' student_id = i + 1 student_grades = [random.randint(30, 100) for _ in range(5)] students.append(Student(student_name, student_id, student_grades)) for student in students: total_score = sum(student.grades) avg_score = total_score / len(student.grades) print(f'学生{student.name} 的总分是 {total_score},平均分是 {avg_score:.2f}') ``` 此脚本展示了如何构建一个简单的学生成绩管理系统,并完成基本的数据汇总功能。 --- #### 3. 三分查算法及其应用 三分查是一种改进型的一维搜索技术,适用于单峰函数极值解等问题。其核心思想是在每次迭代过程中将当前区间划分为三部分,通过两次比较逐步逼近目标位置[^3]。 C++实现如下所示: ```cpp #include <iostream> using namespace std; int ternarySearch(int arr[], int size, int target){ int low=0; int high=size-1; while(low<=high){ int mid1=(low+(high-low)/3); int mid2=(high-(high-low)/3); if(target==arr[mid1]) return mid1; if(target==arr[mid2]) return mid2; if(target<arr[mid1]){ high=mid1-1; } else if(target>arr[mid2]){ low=mid2+1; } else{ low=mid1+1; high=mid2-1; } } return -1; // Not found } ``` 以上代码片段清晰地体现了三分查的工作机制,同时具备较高的运行效率,适合用于大规模有序数组检索场景。 --- #### 4. MATLAB 数组操作练习 MATLAB 是一门广泛应用于科学研究和技术开发的强大工具软件。在其入门阶段的教学材料里,往往包含了大量有关矩阵变换的基础训练项目[^4]。比如对给定二维数组实施逐元素加减乘除运算,或是调用内置函数完成更复杂的数值映射任务等。 示例命令序列可能像这样: ```matlab % 初始化测试矩阵 A 和 B A = magic(3); B = ones(size(A)) * pi; % 执行一系列算术指令 result_addition = A + 10; result_subtraction_complex = result_addition - complex(0, 2); result_multiplication_elementwise = result_subtraction_complex .* B; result_division_right = result_multiplication_elementwise ./ abs(B - A); result_square_elements = sqrt(result_division_right.^2); result_logarithmic_natural = log(exp(result_square_elements)); column_product_A = prod(A, 'all'); min_values_per_column = min(A(:), [], 1); indices_of_minimums = find(min_values_per_column == A); nonzero_linear_indices = find(result_logarithmic_natural ~= 0); [row_nonzeros col_nonzeros] = ind2sub(size(A), nonzero_linear_indices); linspace_vector_example = linspace(3, 4, 5); second_column_extracted = A(:, 2); ``` 每一步都严格遵循特定规则展开,最终达成预期效果。 --- #### 5. 自适应均衡器性能对比研究 最后提到的是通信系统建模方向的一个专题——即采用不同策略调整滤波权重系数以抵消信道干扰现象的研究课题[^5]。具体而言,LMS(Least Mean Square)与 RLS(Recursive Least Squares)作为两类主流递推估计框架被频繁提及。它们各自拥有独特优势但也存在局限之处,需依据实际需权衡选用。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值