第四章 阅读程序
第一课 模拟策略
【NOIP2011】(累加)
例:
#include <bits/stdc++.h>
using namespace std;
int main(){
int i,n,m,ans;
cin>>n>>m;
i=n;
ans=0;
while (i<=m){
ans+=i;
i++;
}
cout<<ans<<endl;
return 0;
}
答案:× × √ √ B A
解析:
第二课 字符处理
【NOIP2009】(二分字符排序)
例:
#include <bits/stdc++.h>
using namespace std;
const int maxn=50;
void getnext(char str[]){
int l=strlen(str),i,j,k,temp;
k=l-2;
while (k>=0 && str[k]>str[k+1]) k--;
i=k+1;
while (i<l && str[i]>str[k]) i++;
temp=str[k];
str[k]=str[i-1];
str[i-1]=temp;
for (i=l-1;i>k;i--){
for (j=k+1;j<i;j++){
if (str[j]>str[j+1]){
temp=str[j];
str[j]=str[j+1];
str[j+1]=temp;
}
}
}
return ;
}
int main(){
char a[maxn];
int n;
cin>>a>>n;
while (n>0){
getnext(a);
n--;
}
cout<<a<<endl;
return 0;
}
答案:× √ √ √ A B
解析:
第三课 枚举算法
【NOIP2013】(判断字符是否为回文)
例:
#include <bits/stdc++.h>
using namespace std;
int main(){
string str;
cin>>str;
int n=str.size();
bool isPlalindrome=true; // isPlalindrome译为:回文数
for (int i=0;i<n/2;i++){
if (str[i]!=str[n-i-1]){
isPlalindrome=false;
break;
}
}
if (isPlalindrome) cout<<"Yes";
else cout<<"No";
return 0;
}
答案:× √ √ √ A B
解析:
【NOIP2013】本题的函数写法
#include <bits/stdc++.h>
using namespace std;
bool is_Plalindrome(string s){
int size=s.size();
for (int i=0;i<size;i++){
if (s[i]!=s[size-i-1]) return false;
}
return true;
} // 判断回文字符串函数
int main(){
string str;
cin>>str;
int n=str.size();
if (is_Plalindrome(str)) cout<<"Yes";
else cout<<"No";
return 0;
}
【NOIP2017】(字符串中第一个仅出现一次的字母)
例:
#include <bits/stdc++.h>
using namespace std;
int main(){
int t[256];
string s;
int i;
cin>>s;
for (i=0;i<256;i++) t[i]=0;
for (i=0;i<s.length();i++) t[s[i]]++;
for (i=0;i<s.length();i++){
if (t[s[i]]==1){
cout<<s[i]<<endl;
return 0;
}
}
cout<<"no";
return 0;
}
答案:× × √ × B B
解析:
![]()
第四课 排序算法
【NOIP2010】(给定两个有序数列,合并成一个新的数列)
例:
#include <bits/stdc++.h>
using namespace std;
const int SIZE=100;
int na,nb,a[SIZE],b[SIZE],i,j,k;
int main(){
cin>>na;
for (i=1;i<=na;i++) cin>>a[i];
cin>>nb;
for (i=1;i<=nb;i++) cin>>b[i];
i=1;
j=1;
while ((i<=na) && (j<=nb)){
if (a[i]<=b[j]){
cout<<a[i]<<' ';
i++;
}
else{
cout<<b[j]<<' ';
j++;
}
}
if (i<=na){
for (k=i;k<=na;k++) cout<<a[k]<<' ';
}
if (j<=nb){
for (k=j;k<=nb;k++) cout<<b[k]<<' ';
}
return 0;
}
答案:√ √ × √ A A
解析:
附:归并排序
1.算法介绍
- 归并排序是一种高效的 分治法(Divide and Conquer)排序算法,核心思想:
- 1️⃣ 分解:将数组递归拆分为最小单位(单个元素)
- 2️⃣ 合并:将有序子数组合并为更大有序数组
- ✅ 时间复杂度:最优/平均/最坏均为 O(n log n)
- ✅ 稳定性:稳定排序(相同元素顺序不变)
- ✅ 适用场景:大数据量、链表排序、外部排序
2. 分治思想图解
初始数组: [38, 27, 43, 3, 9, 82, 10]
↓ 分解
[38, 27, 43] [3, 9, 82, 10]
↓ 分解 ↓ 分解
[38] [27, 43] [3,9] [82,10]
↓ 合并 ↓ 合并
[27, 38, 43] [3,9,10,82]
↓ 合并
[3,9,10,27,38,43,82]
3. 合并操作详解
核心步骤:合并两个有序数组
Left数组: [27, 38, 43] Right数组: [3, 9, 10, 82]
Step1: 比较左首(27) vs 右首(3) → 取较小值 3
Step2: 比较 27 vs 9 → 取 9
Step3: 比较 27 vs 10 → 取 10
Step4: 直接追加左数组:[27,38,43]
结果:[3, 9, 10, 27, 38, 43, 82]
4. C++ 代码实现
#include <bits/stdc++.h>
using namespace std;
int arr[7]={38,27,43,3,9,82,10};
int brr[7];
void merge(int a[],int b[],int l,int mid,int r){
// 合并为有序数列
int i=l,j=mid+1,k=l;
// 从左右两边依次判断较小值进行合并
while (i<=mid && j<=r){
if (a[i]<=a[j]) b[k++]=a[i++];
else b[k++]=a[j++];
}
while (i<=mid) b[k++]=a[i++];
while (j<=r) b[k++]=a[j++];
for (int i=l;i<=r;i++) a[i]=b[i];
}
void mergeSort(int a[],int l,int r){
// 分解原数组
if (l>=r) return ;
// 计算中间值
int mid=(l+r)/2;
mergeSort(a,l,mid); // 左数列
mergeSort(a,mid+1,r); // 右数列
// 合并
merge(arr,brr,l,mid,r);
}
int main(){
mergeSort(0,9); // 左边界和右边界
for (int i=0;i<9;i++) cout<<arr[i]<<' ';
return 0;
}
输出:3 9 10 27 38 43 82
5. 关键点分析
- 递归深度:共 log₂n 层分解
- 合并成本:每层合并需 O(n) 操作
- 空间复杂度:O(n)(临时数组开销)
- 优化策略:
- 小数组用插入排序减少递归开销
- 避免频繁内存分配(全局复用 temp 数组)
6. 与快速排序对比
7. 可视化演示推荐
(动态理解分解与合并过程)
总结
归并排序以时间换空间,凭借稳定且可预测的性能,成为大规模数据排序的基石算法!
第五课 搜索算法
1.二分查找
1.标准二分查找
代码:
#include <bits/stdc++.h>
using namespace std;
const int SIZE=105;
int n,x,arr[SIZE];
int binary_search(int x){
int l=0,r=n;
while (l+1<r){
int mid=(l+r)>>1;
if (x==arr[mid]) return mid;
else if (x>arr[mid]) l=mid;
else r=mid;
}
return -1;
}
int main(){
cin>>n;
for (int i=0;i<n;i++) cin>>arr[i];
cin>>x;
cout<<binary_search(x);
return 0;
}
2.给定两个数组,从A数组中找出B数组中的内容,并按从小到大进行排序
代码:
#include <bits/stdc++.h>
using namespace std;
const int SIZE=10005;
int n,m,arr[SIZE],brr[SIZE];
int binary_search(int x){
int l=0,r=n+1;
while (l+1<r){
int mid=(l+r)>>1;
if (x==arr[mid]) return mid;
else if (x>arr[mid]) l=mid;
else r=mid;
}
return 0;
}
int main(){
cin>>n>>m;
for (int i=1;i<=n;i++) cin>>arr[i];
for (int i=1;i<=m;i++) cin>>brr[i];
sort(arr+1,arr+n+1);
sort(brr+1,brr+m+1);
// 二分查找
for (int i=1;i<=m;i++){
if (binary_search(brr[i])) cout<<brr[i]<<' ';
}
return 0;
}
3.[USACO05FEB] 进击的奶牛
代码:
#include <bits/stdc++.h>
using namespace std;
int n,m,a[100005];
int main(){
cin>>n>>m;
for (int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+n+1);
int l=0,r=a[n]+1,mid;
while (l+1!=r){
mid=(l+r)/2;
int cnt=1,pre=a[1];
for (int i=2;i<=n;i++){
if (a[i]-pre>=mid){
cnt++;
pre=a[i];
}
}
if (cnt>=m) l=mid;
else r=mid;
}
cout<<l;
return 0;
}