P31(AcWing笔记本)
好理解的代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 10010;
int n, m;
int a[N];
int main () {
cin >> n >> m;
for (int i = 1; i <= n; i ++) cin >> a[i];
while (m --) {
int k = n; //用k从后往前找
while (a[k - 1] > a[k]) k --; //找到第一个升序的位置k-1 和 k (k是顶峰)
int t = k; //再从k往后找,
while (a[t + 1] > a[k - 1]) t ++; //找到最小的比a[k - 1]大的数,该循环结束时,a[t]就是最小的比a[k - 1]大的数
swap(a[k - 1], a[t]); // 交换w[k - 1]和w[t]
reverse(a + k, a + n + 1); // 翻转a[k] ~ a[n]这部分降序序列为升序序列
}
for (int i = 1; i <= n; i ++) cout << a[i] << ' ';
puts("");
return 0;
}
做法:
1. 从后往前找到第一个a[k] < a[k + 1]的位置k
2. 在a[k+1 ···n]中找到大于a[k]的最小的数a[t]
3. 交换 a[k]和a[t],交换后可以发现,a[k+1 ···n]是单调递减
4. 将a[k+1 ···n]翻转
y总给的另一种代码
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 10010;
int n, m;
int a[N];
int main () {
cin >> n >> m;
for (int i = 0; i < n; i ++) cin >> a[i];
while (m --) {
int k = n - 2;
while (a[k] > a[k + 1]) k --;
int t = k + 1;
while (t + 1 < n && a[t + 1] > a[k]) t ++;
swap(a[k], a[t]);
reverse(a + k + 1, a + n);
}
for (int i = 0; i < n; i ++) cout << a[i] << ' ';
puts("");
return 0;
}
参考别人的代码1:
#include<bits/stdc++.h>
using namespace std;
const int N=10010;
int n,m;
int q[N];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++) scanf("%d",&q[i]);
while(m--)
{
int k=n-1;
while(q[k]>q[k+1]) k--;
//推出循环时q[k]<q[k+1];
int t=n;
while(q[t]<q[k]&&t>=k) t--;
//int t=k;
//while(t+1<=n&&q[t+1]>q[k]) t++;
swap(q[k],q[t]);
reverse(q+k+1,q+n+1);
}
for(int i=1;i<=n;i++) printf("%d ",q[i]);
return 0;
}
参考别人的代码2:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5+10;
int n,m;
int a[N];
int main(){
cin>>n>>m;
for(int i=0;i<n;i++) cin>>a[i];
while(m--)
{
int i = n-1; //从最后开始
while(a[i-1] > a[i]) i--; //找到第一个能增大字典序的位置,要把i-1处的元素替换成比他大的最小元素
int j = i; //从i处开始向后,找到大于a[i-1]的最小元素(i-1后面必是逆序序列)
while(a[j] > a[i-1]) j++; //让j指向第一个比a[i-1]小的元素,则j-1指向比a[i-1]大的最小元素
swap(a[i-1],a[j-1]); //替换,增大字典序
reverse(a + i, a + n); //i到n-1元素逆置
}
for(int i=0;i<n;i++) cout<<a[i]<<' ';
return 0;
}