T1 求第K小的数(分治)
题目:

用到类似快速排序的分治法。快速排序的思想是把数多次分为三个区间(小于基准数 / 等于基准数 / 大于基准数),再将各个排序好的各个区间拼在一起,就能得到一个排序好的完整数组。
因为分为三个区间后,总数不变,所以直接对原数组进行覆写即可。
快速排序代码:
//qsort (快速排序的核心思想是递归分治)
#include <iostream>
using namespace std;
const int maxx = 100005;
int n,k,a[maxx],b[maxx],c[maxx],d[maxx];
void prework(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
}
void qsort(int l,int r){
if(l>=r){
return;
//len <= 0
}
int t1=0,t2=0,t3=0,mid;
mid = a[(l+r)/2];
for(int i=l;i<=r;i++){
if(a[i]<mid)
b[++t1] = a[i];
else if(a[i]==mid)
c[++t2] = a[i];
else d[++t3] = a[i];
}
for(int i=1;i<=t1;i++)
a[i+l-1] = b[i];
for(int i=1;i<=t2;i++)
a[i+t1+l-1] = c[i];
for(int i=1;i<=t3;i++)
a[i+t1+t2+l-1] = d[i];
qsort(l,l+t1-1);
qsort(l+t1+t2,r);
}
void solve(){
qsort(1,n);
for(int i=1;i<=n;i++) cout<<a[i]<<' ';
}
int main(){
prework();
solve();
}
那么要求无序数组第k小的数,会想到进行排序后直接输出对应下标的那个数。然而直接排序复杂度是O(nlogn),大概是10^8这个级别,排序后交也是只有60分,过不了。
自然想到用二分的思想去找 第k小的数。快速排序是以基准数把数组分为两个部分L 和 R,如果要找第k小的数,若L的右边界的数Lr比k大,那第k小的数就在L中,调用函数继续对L划分即可。找到答案的时候是k等于基准数的时候(基准数是在区间里取的,不会出现没有对应的情况)
代码:
#include <iostream>
using namespace std;
const int maxx = 5e6+5;
int n,k,a[maxx],b[maxx],c[maxx],d[maxx],ans;
void prework(){
cin>>n>>k;
for(int i=0;i<n;i++){
cin>>a[i];
}
}
void qsort(int l,int r){
if(l>=r){
ans = a[l];//边界情况更新答案(当l==r时会直接退出
return;
}
int t1=0,t2=0,t3=0,mid;
mid = a[(l+r)/2];
for(int i=l;i<=r;i++){
if(a[i]<mid)
b[++t1] = a[i];
else if(a[i]==mid)
t2++;//c[++t2] = a[i];
else
d[++t3] = a[i];
}
//分成三个区间 L~i~j~R k<=i时 去搜左边的区间
if(l+t1-1>=k){
for(int i=0;i<t1;i++)
a[l+i] = b[i+1];//fill left
qsort(l,l+t1-1);
}
else if(l+t1+t2<=k){
for(int i=0;i<t3;i++)
a[l+t1+t2+i] = d[i+1];
qsort(l+t1+t2,r);
}
else{
ans = mid;//更新答案
return;
}
}
void solve(){
qsort(0,n-1);
cout<<ans;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(NULL); cout.tie(NULL);
prework();
solve();
return 0;
}
T2 穿越雷区
题目:

样例:

一道搜索题。
代码:
#include <iostream>
#include <queue>
using namespace std;
struct point{
int x,y,k;
};
int movex[5]={0,1,-1,0,0};
int movey[5]={0,0,0,1,-1};
int n,world[105][105],ans=-1;
bool vis[105][105];
queue<point> a;
bool judge(int x,int y,int nx,int ny){
if(world[nx][ny]==2)
return true;
else if(world[x][y]==world[nx][ny])
return false;
return true;
}
void bfs(){
while(!a.empty()){
point temp = a.front();
int x1=temp.x,y1=temp.y,k1=temp.k;
if(world[x1][y1]==2){
ans = k1;
return;
}
for(int i=1;i<=n;i++){
int nx=x1+movex[i];
int ny=y1+movey[i];
if(nx>=1&&nx<=n&&ny>=1&&ny<=n&&judge(x1,y1,nx,ny)&&vis[nx][ny]==0){
vis[nx][ny]=1;
a.push({nx,ny,k1+1});
}
}
a.pop();
}
}
void prework(){
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
char temp; cin>>temp;
if(temp=='B')
world[i][j]=2;
else if(temp=='A')
world[i][j]=3,vis[i][j]=1,a.push({i,j,0});
else if(temp=='+')
world[i][j]=1;
else
world[i][j]=0;
}
}
}
int main(){
prework();
bfs();
cout<<ans;
return 0;
}
T3 KMP字符串匹配 (模板)
题目:

样例:

若文本串长度为n,模式串长度为m,则朴素算法复杂度是o(nm),kmp算法其实就是对朴素算法的优化:当匹配过程中出现失配的情况时,可以跳过小于模式串的长度再进行匹配,需要计算记录回文长度的前缀表做到。
代码:
#include <iostream>
#include <cstring>
using namespace std;
const int l = 1000005;
int next_[l],ans,l1,l2;
char t[l],p[l];
string s1,s2;
void trans(){
l1 = s1.length();
l2 = s2.length();
for(int i=0;i<l1;i++){
t[i+1] = s1[i];
if(i<l2) p[i+1] = s2[i];
}
}
void prefix(){
int k=0;
for(int i=2;i<=l2;i++){
while(k>0 && p[k+1]!=p[i])
k = next_[k];
if(p[k+1]==p[i])
k++;
next_[i]=k;//更新next_前缀表
}
}
void kmp(){
int k=0;
for(int i=1;i<=l1;i++){
while(k>0 && p[k+1]!=t[i]){
k = next_[k];
}
if(p[k+1]==t[i])
k++;
if(k==l2){
cout<<i-l2+1<<endl;
k=next_[k];
}
}
}
int main(){
cin>>s1>>s2;
trans();
prefix();
kmp();
for(int i=1;i<=l2;i++)
cout<<next_[i]<<' ';
return 0;
}