
剑指51.数组中的逆序对【困难】169.多数元素【简单】53.最大子序和【简单】50.Pow(x,n)【中等】4.寻找两个正序数组的中位数【困难】932.漂亮数组【中等】514.自由之路【困难】903.DI 序列的有效排列【困难】327.区间和的个数【困难】...
一、汉诺塔问题
1.1、问题描述
每次只能移动一个圆盘。 大圆盘不能放在小圆盘上面。
1.2、解题思路
如果只有一个圆盘(n=1),直接将它从初始杆子移动到目标杆子。 如果有多个圆盘(n>1),可以将问题分解为三个子问题: 将n-1个圆盘从初始杆子移动到辅助杆子,借助目标杆子。 将第n个圆盘从初始杆子移动到目标杆子。 将n-1个圆盘从辅助杆子移动到目标杆子,借助初始杆子。
1.3、代码示例
#include <iostream>// 函数定义:将n个圆盘从source杆移动到target杆,借助auxiliary杆void hanoi(int n, char source, char auxiliary, char target) {if (n == 1) {// 只有一个圆盘时,直接移动std::cout << "Move disk 1 from " << source << " to " << target << std::endl;} else {// 先将n-1个圆盘从source杆移动到auxiliary杆,借助target杆hanoi(n - 1, source, target, auxiliary);// 移动第n个圆盘std::cout << "Move disk " << n << " from " << source << " to " << target << std::endl;// 再将n-1个圆盘从auxiliary杆移动到target杆,借助source杆hanoi(n - 1, auxiliary, source, target);}}int main() {int n = 3; // 圆盘数量hanoi(n, 'A', 'B', 'C'); // 调用hanoi函数解决问题return 0;}

二、最大子数组和问题
2.1、问题描述
nums,我们需要找到一个连续的子数组,使得子数组的和最大。我们要求返回这个最大的子数组和。
2.2、解题思路
将原始数组分成两半: left
和right
。递归地计算 left
和right
子数组的最大子数组和,分别记为leftMax
和rightMax
。计算横跨左右两个子数组的最大子数组和。从数组中间开始向左右两边扩展,分别计算左边和右边的子数组的最大和。最后将这两个和相加,得到横跨的子数组的最大和,记为 crossMax
。最大子数组和要么在 leftMax
、rightMax
、crossMax
中,要么跨越左右两个子数组。因此,最终的最大子数组和是这三者中的最大值。
2.3、代码示例
#include <iostream>#include <vector>#include <algorithm>int maxCrossingSum(std::vector<int>& nums, int left, int mid, int right) {int leftSum = INT_MIN;int sum = 0;for (int i = mid; i >= left; --i) {sum += nums[i];leftSum = std::max(leftSum, sum);}int rightSum = INT_MIN;sum = 0;for (int i = mid + 1; i <= right; ++i) {sum += nums[i];rightSum = std::max(rightSum, sum);}return leftSum + rightSum;}int maxSubarraySum(std::vector<int>& nums, int left, int right) {if (left == right) {return nums[left];}int mid = (left + right) 2;int leftMax = maxSubarraySum(nums, left, mid);int rightMax = maxSubarraySum(nums, mid + 1, right);int crossMax = maxCrossingSum(nums, left, mid, right);return std::max({leftMax, rightMax, crossMax});}int maxSubArray(std::vector<int>& nums) {if (nums.empty()) {return 0;}int left = 0;int right = nums.size() - 1;return maxSubarraySum(nums, left, right);}int main() {std::vector<int> nums = {-2, 1, -3, 4, -1, 2, 1, -5, 4};int result = maxSubArray(nums);std::cout << "Maximum subarray sum: " << result << std::endl;return 0;}

三、最接近点对问题
3.1、问题描述
3.2、解题思路
首先,对点集 P 按照 x 坐标进行排序,得到一个按 x 坐标递增排列的点集 Px。同时,对点集 P 按照 y 坐标进行排序,得到一个按 y 坐标递增排列的点集 Py。 利用分治法,将点集 Px 分成两部分:左半部分 Pl 和右半部分 Pr,同时也将点集 Py 分成相应的左半部分 Ql 和右半部分 Qr。 递归地在左半部分 Pl 和 Pr 中分别寻找最接近点对(使用相同的算法),得到左半部分的最近点对 d1 和右半部分的最近点对 d2。 找到两个最近点对 d1 和 d2 中距离较小的那一个,记为 delta。 然后,检查以 delta 距离内的所有点,查看是否有更近的点对。这一步可以在 Px 和 Py 中同时进行,因为我们只需要考虑在 delta 范围内的点。 最后,返回最接近点对的距离。
3.3、代码示例
#include <iostream>#include <vector>#include <algorithm>#include <cmath>#include <limits>// 定义一个点的结构体struct Point {double x;double y;};// 按照 x 坐标进行比较的比较函数bool compareX(const Point& p1, const Point& p2) {return p1.x < p2.x;}// 按照 y 坐标进行比较的比较函数bool compareY(const Point& p1, const Point& p2) {return p1.y < p2.y;}// 计算两点之间的欧氏距离double euclideanDistance(const Point& p1, const Point& p2) {double dx = p1.x - p2.x;double dy = p1.y - p2.y;return sqrt(dx * dx + dy * dy);}// 求解最接近点对的函数double closestPairUtil(std::vector<Point>& Px, std::vector<Point>& Py, int left, int right) {if (right - left <= 2) {// 如果点数小于等于3,直接暴力计算最近点对距离double minDistance = std::numeric_limits<double>::max();for (int i = left; i < right; ++i) {for (int j = i + 1; j < right; ++j) {minDistance = std::min(minDistance, euclideanDistance(Px[i], Px[j]));}}return minDistance;}// 将 Px 和 Py 分成左右两部分int mid = (left + right) 2;std::vector<Point> Plx(Px.begin() + left, Px.begin() + mid);std::vector<Point> Prx(Px.begin() + mid, Px.begin() + right);std::vector<Point> Ply, Pry;double midX = Px[mid].x;for (const Point& p : Py) {if (p.x < midX) {Ply.push_back(p);} else {Pry.push_back(p);}}// 递归地计算左右两部分的最近点对距离double delta1 = closestPairUtil(Plx, Ply, 0, mid - left);double delta2 = closestPairUtil(Prx, Pry, 0, right - mid);double delta = std::min(delta1, delta2);// 查找跨越两个子数组的最近点对std::vector<Point> strip;for (const Point& p : Py) {if (fabs(p.x - midX) < delta) {strip.push_back(p);}}// 在 strip 中查找最近点对int stripSize = strip.size();for (int i = 0; i < stripSize; ++i) {for (int j = i + 1; j < stripSize && (strip[j].y - strip[i].y) < delta; ++j) {delta = std::min(delta, euclideanDistance(strip[i], strip[j]));}}return delta;}// 计算最接近点对的主函数double closestPair(std::vector<Point>& points) {int n = points.size();// 将点按照 x 坐标进行排序std::vector<Point> Px = points;std::sort(Px.begin(), Px.end(), compareX);// 将点按照 y 坐标进行排序std::vector<Point> Py = points;std::sort(Py.begin(), Py.end(), compareY);return closestPairUtil(Px, Py, 0, n);}int main() {std::vector<Point> points = {{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}};double minDistance = closestPair(points);std::cout << "最接近点对的距离是:" << minDistance << std::endl;return 0;}

四、矩阵乘法问题
4.1、问题描述
4.2、解题思路
将两个矩阵 A 和 B 分别划分成四个子矩阵,分别记为 A11、A12、A21、A22 以及 B11、B12、B21、B22。这个划分可以通过将原始矩阵分成四个等大小的子矩阵来实现。 使用递归的方式计算子矩阵的乘积,即计算 P1 = A11 * (B12 - B22),P2 = (A11 + A12) * B22,P3 = (A21 + A22) * B11,P4 = A22 * (B21 - B11),P5 = (A11 + A22) * (B11 + B22),P6 = (A12 - A22) * (B21 + B22),P7 = (A11 - A21) * (B11 + B12)。 利用这些子问题的解 P1 到 P7,计算矩阵 C 的四个子矩阵:C11 = P5 + P4 - P2 + P6,C12 = P1 + P2,C21 = P3 + P4,C22 = P5 + P1 - P3 - P7。 最后,将这些子矩阵合并成矩阵 C,即 C = [C11, C12; C21, C22]。
4.3、代码示例
#include <iostream>#include <vector>// 函数用于将两个矩阵相加std::vector<std::vector<int>> matrixAdd(const std::vector<std::vector<int>>& A, const std::vector<std::vector<int>>& B) {int n = A.size();int m = A[0].size();std::vector<std::vector<int>> result(n, std::vector<int>(m));for (int i = 0; i < n; ++i) {for (int j = 0; j < m; ++j) {result[i][j] = A[i][j] + B[i][j];}}return result;}// 函数用于将两个矩阵相减std::vector<std::vector<int>> matrixSubtract(const std::vector<std::vector<int>>& A, const std::vector<std::vector<int>>& B) {int n = A.size();int m = A[0].size();std::vector<std::vector<int>> result(n, std::vector<int>(m));for (int i = 0; i < n; ++i) {for (int j = 0; j < m; ++j) {result[i][j] = A[i][j] - B[i][j];}}return result;}// 函数用于分治矩阵乘法std::vector<std::vector<int>> matrixMultiply(const std::vector<std::vector<int>>& A, const std::vector<std::vector<int>>& B) {int n = A.size();// 如果矩阵大小为1x1,则直接相乘if (n == 1) {std::vector<std::vector<int>> result(1, std::vector<int>(1));result[0][0] = A[0][0] * B[0][0];return result;}// 将矩阵分为四个子矩阵int half_size = n 2;std::vector<std::vector<int>> A11(half_size, std::vector<int>(half_size));std::vector<std::vector<int>> A12(half_size, std::vector<int>(half_size));std::vector<std::vector<int>> A21(half_size, std::vector<int>(half_size));std::vector<std::vector<int>> A22(half_size, std::vector<int>(half_size));std::vector<std::vector<int>> B11(half_size, std::vector<int>(half_size));std::vector<std::vector<int>> B12(half_size, std::vector<int>(half_size));std::vector<std::vector<int>> B21(half_size, std::vector<int>(half_size));std::vector<std::vector<int>> B22(half_size, std::vector<int>(half_size));// 将输入矩阵分割为子矩阵for (int i = 0; i < half_size; ++i) {for (int j = 0; j < half_size; ++j) {A11[i][j] = A[i][j];A12[i][j] = A[i][j + half_size];A21[i][j] = A[i + half_size][j];A22[i][j] = A[i + half_size][j + half_size];B11[i][j] = B[i][j];B12[i][j] = B[i][j + half_size];B21[i][j] = B[i + half_size][j];B22[i][j] = B[i + half_size][j + half_size];}}// 递归计算子矩阵的乘积std::vector<std::vector<int>> P1 = matrixMultiply(A11, matrixSubtract(B12, B22));std::vector<std::vector<int>> P2 = matrixMultiply(matrixAdd(A11, A12), B22);std::vector<std::vector<int>> P3 = matrixMultiply(matrixAdd(A21, A22), B11);std::vector<std::vector<int>> P4 = matrixMultiply(A22, matrixSubtract(B21, B11));std::vector<std::vector<int>> P5 = matrixMultiply(matrixAdd(A11, A22), matrixAdd(B11, B22));std::vector<std::vector<int>> P6 = matrixMultiply(matrixSubtract(A12, A22), matrixAdd(B21, B22));std::vector<std::vector<int>> P7 = matrixMultiply(matrixSubtract(A11, A21), matrixAdd(B11, B12));// 计算结果矩阵的四个分块std::vector<std::vector<int>> C11 = matrixAdd(matrixSubtract(matrixAdd(P5, P4), P2), P6);std::vector<std::vector<int>> C12 = matrixAdd(P1, P2);std::vector<std::vector<int>> C21 = matrixAdd(P3, P4);std::vector<std::vector<int>> C22 = matrixAdd(matrixSubtract(matrixAdd(P5, P1), P3), P7);// 合并结果矩阵std::vector<std::vector<int>> result(n, std::vector<int>(n));for (int i = 0; i < half_size; ++i) {for (int j = 0; j < half_size; ++j) {result[i][j] = C11[i][j];result[i][j + half_size] = C12[i][j];result[i + half_size][j] = C21[i][j];result[i + half_size][j + half_size] = C22[i][j];}}return result;}int main() {// 示例矩阵 A 和 Bstd::vector<std::vector<int>> A = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, {13, 14, 15, 16}};std::vector<std::vector<int>> B = {{17, 18, 19, 20}, {21, 22, 23, 24}, {25, 26, 27, 28}, {29, 30, 31, 32}};// 计算矩阵乘积std::vector<std::vector<int>> result = matrixMultiply(A, B);// 打印结果int n = result.size();for (int i = 0; i < n; ++i) {for (int j = 0; j < n; ++j) {std::cout << result[i][j] << " ";}std::cout << std::endl;}return 0;}

五、多项式乘法问题
5.1、问题描述
A(x) = a_n * x^n + a_(n-1) * x^(n-1) + ... + a_1 * x^1 + a_0B(x) = b_m * x^m + b_(m-1) * x^(m-1) + ... + b_1 * x^1 + b_0
C(x) = A(x) * B(x)
5.2、解题思路
将多项式 A 和 B 均分为两部分,得到:
A(x) = A0(x) + A1(x)B(x) = B0(x) + B1(x)
递归计算四个子问题:
C0(x) = A0(x) * B0(x)C1(x) = A0(x) * B1(x)C2(x) = A1(x) * B0(x)C3(x) = A1(x) * B1(x)
计算结果多项式 C(x) 的系数,其中:
C(x) = C0(x) * x^(n/2) + C1(x) * x^(n/2) + C2(x) * x^(n/2) + C3(x)
5.3、代码示例
#include <iostream>#include <vector>// 函数用于将两个多项式相乘std::vector<int> polynomialMultiply(const std::vector<int>& A, const std::vector<int>& B) {int n = A.size();int m = B.size();// 如果多项式的长度为1,则直接相乘if (n == 1 || m == 1) {std::vector<int> result(n + m - 1, 0);for (int i = 0; i < n; ++i) {for (int j = 0; j < m; ++j) {result[i + j] += A[i] * B[j];}}return result;}// 将多项式 A 和 B 分为两部分int half = std::max(n, m) 2;std::vector<int> A0(A.begin(), A.begin() + std::min(half, n));std::vector<int> A1(A.begin() + std::min(half, n), A.end());std::vector<int> B0(B.begin(), B.begin() + std::min(half, m));std::vector<int> B1(B.begin() + std::min(half, m), B.end());// 递归计算四个子问题std::vector<int> C0 = polynomialMultiply(A0, B0);std::vector<int> C2 = polynomialMultiply(A1, B1);// 计算中间多项式 D(x) = (A0 + A1)(B0 + B1) - C0 - C2std::vector<int> D(n + m - 1, 0);std::vector<int> A0A1(A0);A0A1.insert(A0A1.end(), A1.begin(), A1.end());std::vector<int> B0B1(B0);B0B1.insert(B0B1.end(), B1.begin(), B1.end());std::vector<int> C1 = polynomialMultiply(A0A1, B0B1);for (int i = 0; i < n + m - 1; ++i) {D[i] = C1[i] - C0[i] - C2[i];}// 合并结果std::vector<int> result(n + m - 1, 0);for (int i = 0; i < n + m - 1; ++i) {result[i] = C0[i] + D[i] * (1 << half) + C2[i] * (1 << (2 * half));}return result;}int main() {// 示例多项式 A 和 B 的系数std::vector<int> A = {1, 2, 3};std::vector<int> B = {4, 5, 6};// 计算多项式乘积std::vector<int> result = polynomialMultiply(A, B);// 打印结果for (int i = 0; i < result.size(); ++i) {std::cout << result[i];if (i < result.size() - 1) {std::cout << "x^" << i << " + ";}}return 0;}
六、寻找中位数问题
6.1、问题描述
6.2、解题思路
选择数组中的一个元素作为"枢轴"(pivot)。 将数组中小于枢轴的元素放在枢轴的左边,将大于枢轴的元素放在枢轴的右边。这个过程叫做分区(partition)。 如果枢轴的位置恰好是数组的中间位置(即,它的左边有 n/2 个元素,右边也有 n/2 个元素),那么枢轴就是中位数,直接返回。 如果枢轴的位置在中位数的左边(即,它的左边有 n/2 个元素,右边有 n/2+1 个元素),那么中位数必然在枢轴的右边,递归地在右半部分查找中位数。 如果枢轴的位置在中位数的右边(即,它的左边有 n/2+1 个元素,右边有 n/2 个元素),那么中位数必然在枢轴的左边,递归地在左半部分查找中位数。
6.3、代码示例
#include <iostream>#include <vector>#include <algorithm>using namespace std;int partition(vector<int>& nums, int left, int right) {int pivot = nums[right]; // 选择最右边的元素作为枢轴int i = left - 1; // 左边界的前一个位置for (int j = left; j < right; j++) {if (nums[j] <= pivot) {i++;swap(nums[i], nums[j]);}}swap(nums[i + 1], nums[right]); // 将枢轴放在正确的位置return i + 1;}int findMedian(vector<int>& nums, int left, int right, int k) {if (left == right) {return nums[left];}int pivotIndex = partition(nums, left, right);int count = pivotIndex - left + 1;if (count == k) {return nums[pivotIndex];} else if (count < k) {return findMedian(nums, pivotIndex + 1, right, k - count);} else {return findMedian(nums, left, pivotIndex - 1, k);}}double findMedian(vector<int>& nums) {int n = nums.size();if (n % 2 == 0) {int median1 = findMedian(nums, 0, n - 1, n 2);int median2 = findMedian(nums, 0, n - 1, n 2 + 1);return (static_cast<double>(median1) + static_cast<double>(median2)) 2.0;} else {return findMedian(nums, 0, n - 1, n 2 + 1);}}int main() {vector<int> nums = {3, 1, 4, 2, 5};double median = findMedian(nums);cout << "Median: " << median << endl;return 0;}

七、最近邻问题
7.1、问题描述
7.2、解题思路
如果点的数量小于等于3个(或其他合适的小规模),直接计算它们之间的距离并返回最小的距离对。 如果点的数量大于3个,将点集分成两部分,分别处理左边和右边的子集。 递归地找到左边子集和右边子集中的最近邻点对,分别记为(d1, p1)和(d2, p2)。 计算左边子集和右边子集之间的最短距离,记为d。 如果d1小于d2,则最近邻点对是(d1, p1);否则,最近邻点对是(d2, p2)。 最后,需要考虑跨越左右两个子集的最近邻点对,这个距离不会超过d。
7.3、代码示例
#include <iostream>#include <vector>#include <cmath>#include <algorithm>#include <limits>using namespace std;struct Point {double x, y;};bool compareX(const Point& p1, const Point& p2) {return p1.x < p2.x;}bool compareY(const Point& p1, const Point& p2) {return p1.y < p2.y;}double euclideanDistance(const Point& p1, const Point& p2) {double dx = p1.x - p2.x;double dy = p1.y - p2.y;return sqrt(dx * dx + dy * dy);}pair<Point, Point> closestPair(vector<Point>& points, int left, int right) {if (right - left <= 3) {double minDistance = numeric_limits<double>::max();pair<Point, Point> closest;for (int i = left; i < right; i++) {for (int j = i + 1; j < right; j++) {double dist = euclideanDistance(points[i], points[j]);if (dist < minDistance) {minDistance = dist;closest = {points[i], points[j]};}}}return closest;}int mid = (left + right) / 2;pair<Point, Point> leftClosest = closestPair(points, left, mid);pair<Point, Point> rightClosest = closestPair(points, mid, right);double minDistance = min(euclideanDistance(leftClosest.first, leftClosest.second),euclideanDistance(rightClosest.first, rightClosest.second));vector<Point> strip;for (int i = left; i < right; i++) {if (abs(points[i].x - points[mid].x) < minDistance) {strip.push_back(points[i]);}}sort(strip.begin(), strip.end(), compareY);for (int i = 0; i < strip.size(); i++) {for (int j = i + 1; j < strip.size() && strip[j].y - strip[i].y < minDistance; j++) {double dist = euclideanDistance(strip[i], strip[j]);if (dist < minDistance) {minDistance = dist;leftClosest = {strip[i], strip[j]};}}}return min(leftClosest, rightClosest);}pair<Point, Point> findClosestPair(vector<Point>& points) {sort(points.begin(), points.end(), compareX);return closestPair(points, 0, points.size());}int main() {vector<Point> points = {{0, 0}, {1, 1}, {2, 2}, {3, 3}, {4, 4}};pair<Point, Point> closest = findClosestPair(points);cout << "Closest pair: (" << closest.first.x << ", " << closest.first.y << ") and ("<< closest.second.x << ", " << closest.second.y << ")" << endl;return 0;}
文章转载自阿Q正砖,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




