二分检索(分治法)
题目大意
给定一个大小为 \(n\) 的递增整数序列 \(L\),使用二分查找法查找任意元素 \(x\) 在序列中的位置 \(k\) (即序列中的第几个元素),若元素不存在则返回 -1。要求编写程序实现二分查找算法,并对其时间复杂度和空间复杂度进行分析,同时通过实验评估算法性能。
解法描述
算法思想
二分查找算法基于分治思想,适用于有序数组。其核心是将待查找区间不断二分,通过比较中间元素与目标元素的大小关系,确定目标元素可能存在的新区间,逐步缩小查找范围,直到找到目标元素或确定其不存在。
实现方式
程序中,先接收输入的序列大小 \(n\)、序列 \(L\) 以及要查找的元素 \(x\)。初始化左右指针
left = -1和right = n,在left < right的循环中,计算中间元素下标mid = (left + right) / 2。若a[mid] >= x,说明目标元素可能在左半部分,更新right = mid;若a[mid] < x,则目标元素在右半部分,更新left = mid + 1。循环结束后,判断a[left]是否等于目标元素x,若相等则返回left,否则返回 -1。复杂度分析
- 时间复杂度:每次迭代都将待查找区间减半,假设序列大小为 \(n\),最多需要进行 \(\log n\) 次迭代就能找到目标元素或确定其不存在,所以时间复杂度为 \(O(\log n)\)。
- 空间复杂度:算法执行过程中,除输入数据外,仅使用了几个辅助变量(如
left、right、mid),这些变量占用的空间不随输入规模 \(n\) 的变化而变化,因此空间复杂度为 \(O(1)\)。
1 |
|
矩阵乘法(分治法)
题目大意
给定两个矩阵 \(A\) 和 \(B\),使用分治法实现矩阵乘法,并与朴素矩阵乘法算法进行比较。要求编写程序实现相关算法,分析算法的正确性、时间复杂度和空间复杂度,并通过实验测试评估算法性能。
解法描述
算法思想
- 朴素矩阵乘法:根据矩阵乘法定义,结果矩阵 \(C\) 的每个元素 \(C_{ij}\) 是矩阵 \(A\) 的第 \(i\) 行与矩阵 \(B\) 的第 \(j\) 列对应元素乘积之和。通过三重循环遍历实现,时间复杂度较高,为 \(O(n^3)\)。
- Strassen 分治算法:基于分治策略,将大矩阵乘法问题分解为多个小规模子矩阵乘法问题。把输入矩阵 \(A\) 和 \(B\) 各划分为四个大小相等的子矩阵,通过特定的加减法和 7 次递归的子矩阵乘法,再进行线性组合得到结果矩阵。这种方法减少了乘法次数,理论上时间复杂度为 \(O(n^{2.7})\)。
实现方式
- 矩阵表示:使用二维向量
vector<vector<int>>表示矩阵,方便对矩阵元素进行访问和操作。 - 辅助函数:实现矩阵加法
matrixAdd和减法matrixSubtract函数,用于 Strassen 算法中矩阵的加减运算;实现朴素矩阵乘法matrixMultiply函数,通过三重循环计算结果矩阵。 - Strassen 算法实现:在
strassen函数中,先处理矩阵规模为 2 的基本情况,直接调用朴素矩阵乘法。对于更大规模矩阵,将其分割为子矩阵,计算中间矩阵\(S_i\) ,递归计算 7 个乘积矩阵 \(M_i\) ,最后通过线性组合得到结果矩阵 \(C\) 的四个子矩阵 \(C_{11}\)、\(C_{12}\)、\(C_{21}\)、\(C_{22}\),并组合成最终结果矩阵。
- 矩阵表示:使用二维向量
复杂度分析
- 朴素矩阵乘法:
- 时间复杂度:有三层嵌套循环,每层循环次数都为矩阵大小 \(n\),所以时间复杂度为 \(O(n^3)\)。
- 空间复杂度:仅使用一个结果矩阵存储最终乘积,空间复杂度为 \(O(n^2)\)。
- Strassen 分治算法:
- 时间复杂度:通过减少乘法次数,理论时间复杂度降为 \(O(n^{2.7})\),但由于常数项较大,在小规模矩阵时效率可能不如朴素算法。
- 空间复杂度:与朴素矩阵乘法相同,都需要一个结果矩阵存储最终结果,空间复杂度为 \(O(n^2)\)。
- 朴素矩阵乘法:
1 |
|
第 K 小元素(分治法)
题目大意
给定一个长度为 \(n\) 的整数序列,找出其中第 \(k\) 小的元素。要求运用分治法思想,编写程序实现该功能,并对算法的正确性、时间复杂度和空间复杂度进行分析,通过实验测试验证算法。
解法描述
算法思想
借鉴快速排序的分区思想,将序列划分为两部分。通过不断递归,在合适的子序列中查找第 \(k\) 小的元素。对于长度较小(小于等于 5)的子序列,直接排序后获取第 \(k\) 小元素;对于长度大于 5 的子序列,先划分为多个大小为 5 的子序列,找到这些子序列中位数的中位数作为分界点,根据分界点与\(k\)的关系,确定下一步搜索的子序列。
实现方式
程序中,
paration函数实现类似快速排序的分区操作,以给定元素k(这里是中位数)为基准,将数组分为两部分,使得左边元素小于k,右边元素大于k,并返回分界点位置。select函数用于递归查找第\(k\)小的元素,当子序列长度小于等于 5 时,直接排序返回第\(k\)小元素;否则,将子序列划分为大小为 5 的子序列,排序后将中位数置于数组前部分,递归找到中位数的中位数x,以x为基准分区,根据k与分区点位置的关系,在左半部分或右半部分继续递归查找。复杂度分析
- 时间复杂度:每次递归都能将搜索范围缩小,虽然每次递归处理的子序列规模不同,但总体上递归深度不超过 \(\log n\),且每次分区操作时间复杂度为线性 \(O(n)\),所以算法时间复杂度为 \(O(n)\)。
- 空间复杂度:主要取决于递归调用栈的深度,由于每次递归序列规模减半,递归栈深度为 \(O(\log n)\),且没有使用其他额外数据结构,所以空间复杂度为 \(O(\log n)\)。
1 |
|