目录
一,分治
分治,字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,
如果子问题的答案都求出来了,就可以求出原问题的答案。
二,经典分治问题和算法
1,二分、三分
二分法_两个单峰函数的和是单峰函数吗_csuzhucong的博客-CSDN博客
2,快速乘法、快速幂、矩阵快速幂
快速乘法、快速幂、矩阵快速幂_给定x,求fx对1000007取余的结果_csuzhucong的博客-CSDN博客
3,汉诺塔
4,线性时间选择算法
其中,平均运行时间为O(n)的算法,和最坏运行时间为O(n)的算法,都是分治算法。
5,归并排序、快速排序、桶排序
常见排序算法_计算排序_csuzhucong的博客-CSDN博客
大学算法课实验:
编写一个简单的程序,实现归并排序。
#include<iostream>
using namespace std;
void merge(int list[],int left,int m,int right)
{
int b[10];
int i=left,j=m+1,k=left;
while(i<=m && j<=right)
{
if(list[i]<list[j])
b[k++]=list[i++];
else b[k++]=list[j++];
}
if(i>m)
for(int q=j;q<=right;q++)b[k++]=list[q];
else for (int q=i;q<=m;q++)b[k++]=list[q];
for(int ii=left;ii<=right;ii++)
{
list[ii]=b[ii];
}
}
void mergeSort(int list[],int left,int right)
{
if(left<right)
{
int i=(left+right)/2;
mergeSort(list,left,i);
mergeSort(list,i+1,right);
merge(list,left,i,right);
}
}
int main()
{
int list[10];
for(int i=0;i<10;i++)
{
cin>>list[i];
}
mergeSort(list,0,9);
for(int i=0;i<10;i++)
{
cout<<list[i]<<" ";
}
system("pause>nul");
return 0;
}
编写一段程序,实现快速排序。
#include<iostream>
using namespace std;
int par(int a[],int p,int r)
{
int i=p,j=r+1;
int x=a[p];
while(1)
{
while(a[++i]<x && i<r);
while(a[--j]>x);
if(i>=j)break;
int te=a[i];
a[i]=a[j];
a[j]=te;
}
a[p]=a[j];
a[j]=x;
return j;
}
void qSort(int list[],int p,int r)
{
if(p<r)
{
int q=par(list,p,r);
qSort(list,p,q-1);
qSort(list,q+1,r);
}
}
int main()
{
int list[10];
for(int i=0;i<10;i++)
{
cin>>list[i];
}
qSort(list,0,9);
for(int i=0;i<10;i++)
{
cout<<list[i]<<" ";
}
system("pause>nul");
return 0;
}
6,循环赛日程表
大学算法课实验:
设有n=2k个运动员要进行网球循环赛。现要设计一个满足以下要求的比赛日程表:(1)每个选手必须与其它n-1个选手各赛一次(2)每个选手一天只能赛一场(3)循环赛进行n-1天。
#include<iostream>
#include<iomanip>
using namespace std;
int main()
{
int k;
while (cin >> k)
{
int n = 1;
for (int i = 1; i <= k; i++)n *= 2;
int **p;
p = new int*[n + 1];
for (int i = 0; i <= n; i++)
{
p[i] = new int[n + 1];
}
for (int i = 1; i <= n; i++)p[1][i] = i;
int m = 1;
for (int s = 1; s <= k; s++)
{
n /= 2;
for (int t = 1; t <= n; t++)
for (int i = m + 1; i <= 2 * m; i++)
for (int j = m + 1; j <= 2 * m; j++)
{
int temp = j + (t - 1)*m * 2;
p[i][temp] = p[i - m][temp - m];
p[i][temp - m] = p[i - m][temp];
}
m *= 2;
}
n = 1;
for (int i = 1; i <= k; i++)n *= 2;
for (int i = 1; i <= n; i++)
{
cout << endl << setw(2) << p[i][1] << " ";
for (int j = 2; j <= n; j++)
{
cout << setw(4) << p[i][j] << " ";
}
}
}
system("pause>nul");
return 0;
}
7,二叉树遍历
三,OJ实战
力扣 95. 不同的二叉搜索树 II
二叉搜索树(BST)_拆分二叉搜索树_csuzhucong的博客-CSDN博客
力扣 剑指 Offer 40. 最小的k个数
输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
示例 1:
输入:arr = [3,2,1], k = 2
输出:[1,2] 或者 [2,1]
示例 2:
输入:arr = [0,1,2,1], k = 1
输出:[0]
限制:
0 <= k <= arr.length <= 10000
0 <= arr[i] <= 10000
分析:
类似线性时间选择算法 线性时间选择算法_csuzhucong的博客-CSDN博客
template<typename T>
bool cmp(T a, T b)
{
return a < b;
}
template<typename T>
int Partition(vector<T>& arr, int start, int end) //[start,end]闭区间
{
T x = arr[end];
int i = start - 1,j;
for (j = start; j < end; j++) {
if (cmp(arr[j], x)) {
++i;
T tmp=arr[j];
arr[j]=arr[i],arr[i]=tmp;
}
}
++i;
T tmp=arr[j];
arr[j]=arr[i],arr[i]=tmp;
return i;
}
class Solution {
public:
vector<int> getLeastNumbers(vector<int>& arr, int start, int end, int k) {
vector<int>ans;
if(start>end || k<=0 || k>end-start+1)return ans;
int part = Partition(arr, start, end);
if (k < part - start + 1)return getLeastNumbers(arr, start, part-1, k);
ans=getLeastNumbers(arr, part+1, end,k-part+start-1);
ans.resize(k);
for(int i=start;i<=part;i++)ans[i+k-part-1]=arr[i];
return ans;
}
vector<int> getLeastNumbers(vector<int>& arr, int k) {
return getLeastNumbers(arr,0,arr.size()-1,k);
}
};
力扣 932. 漂亮数组
对于某些固定的 N,如果数组 A 是整数 1, 2, ..., N 组成的排列,使得:
对于每个 i < j,都不存在 k 满足 i < k < j 使得 A[k] * 2 = A[i] + A[j]。
那么数组 A 是漂亮数组。
给定 N,返回任意漂亮数组 A(保证存在一个)。
示例 1:
输入:4
输出:[2,1,4,3]
示例 2:
输入:5
输出:[3,1,2,5,4]
提示:
1 <= N <= 1000
思路:
把奇数和偶数各放一边,然后两边都可以归结为同样的问题。
class Solution {
public:
vector<int> beautifulArray(int N) {
if(N<=1){
vector<int>ans(1);
ans[0]=1;
return ans;
}
vector<int>a=beautifulArray(N/2);
vector<int>b=beautifulArray(N-N/2);
for(int i=0;i<a.size();i++)a[i]*=2;
for(int i=0;i<b.size();i++)b[i]=b[i]*2-1;
return FvecJoin(a,b);
}
};
力扣 42. 接雨水
题目:
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图。
示例:
输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6
思路一:分治
代码:
class Solution {
public:
int getMax(vector<int>& height, int i, int j)
{
int ansMax = -1, ans = -1;
for (int k = i; k <= j; k++){
if (ansMax < height[k]){
ans = k, ansMax = height[k];
}
}
return ans;
}
int getSum(vector<int>& height, int i,int j)
{
int ans = 0;
for (int k = i; k <= j; k++)ans += height[k];
return ans;
}
int trap(vector<int>& height,int i,int j) {
if (j - i <= 1)return 0;
int k = getMax(height, i + 1, j - 1);
if (height[k] <= height[i] && height[k] <= height[j]){
return min(height[i], height[j])*(j - i) + max(height[i], height[j]) - getSum(height, i, j);
}
return trap(height, i, k) + trap(height, k, j);
}
int trap(vector<int>& height) {
if (height.size() < 2)return 0;
return trap(height, 0, height.size() - 1);
}
};
思路二:
其实可以直接算出每个位置最终的接水量。
每个位置最终的高度,等于两边的最高高度的较小值。
力扣 2936. 包含相等值数字块的数量
给定一个整数数组 nums
,其 下标从 0 开始。对于 nums
,有以下性质:
- 所有相同值的元素都是相邻的。换句话说,如果存在两个下标
i < j
,使得nums[i] == nums[j]
,那么对于所有下标k
,满足i < k < j
,都有nums[k] == nums[i]
。
由于 nums
是一个非常大的数组,这里提供了一个 BigArray
类的实例,该实例具有以下函数:
int at(long long index)
: 返回nums[i]
的值。long long size()
: 返回nums.length
。
让我们把数组分成 最大 的块,使得每个块包含 相等的值。返回这些块的数量。
请注意,如果要使用自定义测试测试解决方案,对于 nums.length > 10
的测试行为是未定义的。
示例 1:
输入:nums = [3,3,3,3,3] 输出:1 解释:这里只有一个块,也就是整个数组(因为所有数字都相等),即:[3,3,3,3,3]。因此答案是 1。
示例 2:
输入:nums = [1,1,1,3,9,9,9,2,10,10] 输出:5 解释:这里有 5 个块: 块号 1: [1,1,1,3,9,9,9,2,10,10] 块号 2: [1,1,1,3,9,9,9,2,10,10] 块号 3: [1,1,1,3,9,9,9,2,10,10] 块号 4: [1,1,1,3,9,9,9,2,10,10] 块号 5: [1,1,1,3,9,9,9,2,10,10] 因此答案是 5。
示例 3:
输入:nums = [1,2,3,4,5,6,7] 输出:7 解释:由于所有数字都是不同的,这里有 7 个块,每个元素代表一个块。因此答案是 7。
提示:
1 <= nums.length <= 1015
1 <= nums[i] <= 109
- 在生成的输入中所有相同值的元素是相邻的。
nums
的所有元素之和最多为1015
。
/**
* Definition for BigArray.
* class BigArray {
* public:
* BigArray(vector<int> elements);
* int at(long long index);
* long long size();
* };
*/
class Solution {
public:
int countBlocks(BigArray* nums) {
long long len = nums->size();
return countBlocks(nums, 0, len - 1, nums->at(0), nums->at(len - 1));
}
int countBlocks(BigArray* nums, long long low, long long high, int x, int y) {
if (x == y)return 1;
long long mid = (low + high) / 2;
int a = nums->at(mid), b = nums->at(mid + 1);
int ans = countBlocks(nums, low, mid, x, a) + countBlocks(nums, mid + 1, high, b, y);
if (a == b)ans--;
return ans;
}
};