Acwing算法基础
课下:
1理解思想
2背写代码模板
3课后题目 —检验掌握程度
1.1排序
1)快速排序
算法思想:
1交换排序。设置两个分别指向首和尾的指针 并设置一个中间值(一般设置队首),将左指针不断向右找,知道l < pivot 右指针向左找, 直到 r > pivot.然后交换.递归 直到只有一个数据或者无数据。
#include<iostream>`
`using namespace std;`
`void quick_sort(int q[] , int l, int r){`
`if( l >= r)return ;`
`int i= l - 1 , j = r + 1 , povit = q[l];`
`while(i < j){`
`do i++; while(q[i] < povit);`
`do j--; while(q[j] > povit);`
`if(i < j) swap(q[i],q[j]);`
`}`
`quick_sort(q, l, j);`
`quick_sort(q, j+1, r);`
`}`
`int main()`
`{`
`int n;`
`cin>>n;`
`int str[n];`
`for(int i=0;i<n;i++){`
`cin>>str[i];`
`}`
`quick_sort(str,0,n-1);`
`for(int i=0;i<n;i++){`
`cout<<str[i]<<" ";`
`}`
`cout<<endl;`
`return 0;`
`}`
2)归并排序
算法思想:双指针 、 分治 、递归
1)以中间点mid 为分界点
2)递归排序Left Right
3)将左右两个排序后的数组合二为一
#include<bits/stdc++.h>
using namespace std;
int t;
void merge_sort(int q[], int tmp[] ,int left, int right,int t)
{
//只有一个元素不用继续分
if(left >= right)return ;
//找到中间值
int mid = (left + right)/2;
//对左边划分
merge_sort(q,tmp,left,mid,t);
//对右边划分
merge_sort(q,tmp,mid+1,right,t);
//进行归并排序
int l_pos = left,r_pos = mid + 1, pos = left;
//将左右两个部分合二为一
while(l_pos <= mid&&r_pos <= right){
if(q[l_pos] < q[r_pos])tmp[pos++] = q[l_pos++];
else tmp[pos++] = q[r_pos++];
}
//左边有剩余元素
while(l_pos <= mid ) tmp[pos++] = q[l_pos++];
//右边右元素
while(r_pos <= right ) tmp[pos++] = q[r_pos++];
t=left;
while(left <= right){
// if(tmp[left]==tmp[left+1]){
// q[t] = tmp[left];
// left++;
// }else{
q[t] = tmp[left];
left++;t++;
// }
}
}
int main()
{
/*
1 - 1000 的 数据用数组存储
*/
int str[10100],tmp[10100];
int n,t=0;
cin>>n;
for(int i=0;i<n;i++){
cin>>str[i];
}
merge_sort(str,tmp,0,n-1,t);
// cout<<t<<endl;
for(int i=0;i<n;i++){
cout<<str[i]<<" ";
}
cout<<endl;
}
1.2二分
整数二分
浮点数二分
1.3高精度
高精度加法 A(length(A)<1.0e9) + B(length(A)<1.0e9) = C
解法 1)将A和B逆序存储在动态数组里(vector<>)
2)将两个数据相加的结果存储在容器C里
#include<iostream>
#include<vector>
using namespace std;
//实现A+B
vector<int> add(vector<int>&A,vector<int>&B)
{
vector<int>C;
if(A.size()-1 < B.size()-1 )return add(B,A);
int t = 0;
for(int i = 0; i < A.size(); i++)
{
t += A[i];
if(i < B.size()) t += B[i];
C.push_back(t%10);
t = t/10;
}
if(t) C.push_back(1);
return C;
}
int main()
{
//定义两个动态数组
vector<int>A,B;
string a,b;
//string 定义的字符串 可直接当字符数组用
//将输入的数据逆序存储在A\B数组里
cin>>a>>b;//a = "123456"
for(int i = a.size() - 1; i >= 0; i--)A.push_back(a[i] - '0');
for(int i = b.size() - 1; i >= 0; i--)B.push_back(b[i] - '0');
//auto(自动,automatic)是存储类型标识符,表明变量"自动"具有本地范围,
//块范围的变量声明(如for循环体内的变量声明)默认为auto存储类型。
vector<int > C = add(A,B); //A = [6,5,4,3,2,1];
for(int i= C.size()-1; i >= 0; i--)
{
cout<<C[i];
}
}
高精度减法 A - B =C
解法: 1)将A、B逆序存储到动态数组vector里
2)判断 A 与 B 的 值谁大 较大的在前
3)编写减法函数 : 如果 A[i] < b[i] t = -1;
#include<bits/stdc++.h>
using namespace std;
//判断A 与 B 的关系
bool cmp(vector<int> A , vector<int> B)
{
if(A.size() != B.size())return A.size() > B.size();
for(int i = 0; i < A.size(); i++)
{
if(A[i] != B[i]) return A[i] > B[i] ;
}
}
//A - B
vector<int> subtraction(vector<int> &A,vector<int> &B)
{
vector<int> C;
//A - B
int t = 0;
/*
A > B 200 - 50 = 150;
*/
for(int i = 0; i < A.size() ; i++)
{
t = A[i] - t;
if(i < B.size()) t -= B[i] ;
C.push_back((t+10)%10);
if(t<0)t = 1;
else t = 0;
}
//会出现003的现象
while(C.size() > 1 && C.back()==0 ) C.pop_back();
return C;
}
int main()
{
string a,b;//a = "12345" b=" 66 "
cin>>a>>b;
vector<int> A,B;
//将A、B逆序存储到动态数组A,B里
for(int i = a.size() - 1; i >= 0; i--)A.push_back(a[i] - '0');
for(int i = b.size() - 1; i >= 0; i--)B.push_back(b[i] - '0');
//将较大的数放在减数位置
if(cmp(A,B))
{
vector<int> C = subtraction(A , B);
for(int i = C.size() -1; i>=0; i--)cout<<C[i];
}
else
{
vector<int> C = subtraction(B , A) ;
cout<<"-";
for(int i = C.size() -1; i>=0; i--)cout<<C[i];
}
return 0;
}
高精度乘法 A * b = C
思想:从 高精度A 的第一位开始,乘b, 加上进位t ,
模10放进数组,直到t = 0, i = A.size
#include<bits/stdc++.h>
using namespace std;
//乘法 t负责进位
vector<int> mul(vector<int> &A, int b)
{
vector<int> C;
int t = 0;
for(int i = 0; i < A.size() || t; i++)
{
if(i < A.size()) t += A[i] * b;
C.push_back(t % 10);
t /= 10;
}
while(C.size() > 1 && C.back() == 0)C.pop_back();
return C;
}
int main()
{
//乘法 A * b
string a ;
int b;
cin>>a>>b;
vector<int> A;
for(int i = a.size() - 1; i >= 0 ; i--)A.push_back(a[i] - '0');
vector<int> C = mul(A , b);
for(int i = C.size() - 1; i >= 0; i--)cout<<C[i];
return 0;
}
高精度除低精度 A / b = C
思想:
1.4前缀和与差分
前缀和
一维前缀和 —— 模板题 AcWing 795. 前缀和
S[i] = a[1] + a[2] + … a[i]
a[l] + … + a[r] = S[r] - S[l - 1]
二维前缀和 —— 模板题 AcWing 796. 子矩阵的和
S[i, j] = 第i行j列格子左上部分所有元素的和
以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵的和为:
S[x2, y2] - S[x1 - 1, y2] - S[x2, y1 - 1] + S[x1 - 1, y1 - 1]
一维差分
在a[L,R] + C
b[l] += c;
b[r+1] -= c;
二维差分
insert(int x1, int y1, int x2, int y2, int c)
{
b[x][y] += c;
b[x1][y2+1] -= c;
b[x2+1][y1] -= c;
b[x2+1][y2+1] += c;
}
1.5双指针算法
for (int i = 0, j = 0; i < n; i ++ )
{
while (j < i && check(i, j)) j ++ ;
// 具体问题的逻辑
}
常见问题分类:
(1) 对于一个序列,用两个指针维护一段区间
(2) 对于两个序列,维护某种次序,比如归并排序中合并两个有序序列的操作
class Solution {
public:
int longestSubstringWithoutDuplication(string s) {
int d[1010];
int res = 0;
for(int i = 0 , j = 0; i < s.length(); i++)
{
d[s[i] - 'a']++;
//从 j 到 i 是否有相同的字符
while(d[s[i] - 'a'] > 1)
{
d[s[j] - 'a']--;
j++;
}
res = max(res,i-j+1);
}
return res;
}
};