前言
复试时存在有道云的笔记,整理一下,将来还能用。
第二章 暴力求解
2.1 枚举
2.1.3 输入格式
函数格式:
include <iostream>
#include <cstdio>
#include <algorithm>//算法包
using namespace std;
int main(){
return 0;
}
1.多组输入,未知组数
#include "stdio.h"
int main(){
int a,b;
while(scanf("%d%d",&a,&b) != EOF){//多组输入,未知组数
printf("%d\n",a+b);
}
return 0;
}
2.多组输入,指定组数
#include "stdio.h"
int main(){
int a,b,n;
scanf("%d",&n);
while(n--){//多组输入,指定组数
scanf("%d%d",&a,&b);
printf("%d\n",a+b);
}
return 0;
}
3.多组输入,指定输出停止
#include "stdio.h"
int main(){
int a,b;
while(scanf("%d%d",&a,&b) != EOF){//多组输入
if(a == 0 && b == 0){//指定输出停止
break;
}
printf("%d\n",a+b);
}
return 0;
}
2.2 模拟
图形模拟
日期模拟
其他模拟
2.2.1 图形排版1:【例题2.4】输出梯形
输入一个高度h,输出一个高为h,上底边为h的梯形。
思路:1.行列数 2.空格数,星号数
#include "stdio.h"
int main(){
int h;
while(scanf("%d",&h) != EOF){
int row = h;
int col = h + 2 * (h-1);
for(int i = 0;i<row;i++){//控制行数
for(int j = 0;j<col;j++){
if(j<col - (h+2*i)) {
printf(" ");
}else{
printf("*");
}
}
printf("\n");
}
}
return 0;
}
2.2.1 图形排版2:【例题2.5】叠筐
题目描述:把一个个大小差一圈的筐叠上去,是的从上往下看时,边框花色交错。
2.2.2 日期问题1:【例题2.6】今年的第几天
/*
* 输入年、月、日,计算该天是本年的第几天。
*/
#include "stdio.h"
int a[2][13]={{0,31,28,31,30,31,30,31,31,30,31,30,31},
{0,31,29,31,30,31,30,31,31,30,31,30,31}};
bool IsLeapYear(int year){
if((year%4==0&&year%100!=0)||(year%400==0)){
return 1;
}else{
return 0;
}
}
int main(){
int year,month,day;
while(scanf("%d %d %d",&year,&month,&day) != EOF){
int number = 0;
int row = IsLeapYear(year);
for(int i = 0;i<month;i++){
number += a[row][i];
}
number+=day;
printf("%d\n",number);
}
}
2.2.2 日期问题2:【例题2.7】打印日期
/*
* 给出年份m和一年中的第n天,算出第n天是几月几号。输入:2000 3。输出:2000-01-03
*/
#include "stdio.h"
int a[2][13]={{0,31,28,31,30,31,30,31,31,30,31,30,31},
{0,31,29,31,30,31,30,31,31,30,31,30,31}};
bool IsLeapYear(int year){
if((year%4==0&&year%100!=0)||(year%400==0)){
return 1;
}else{
return 0;
}
}
int main(){
int year,number;
while(scanf("%d%d",&year,&number) != EOF){
int month = 1,day;
int row = IsLeapYear(year);
while(number-a[row][month]>0){
number=number-a[row][month];
month++;
}
day = number;
printf("%d-%02d-%02d",year,month,day);//%02d意思是输出两位整数,不足则补0
}
}
2.2.3 其他模拟:【例题2.10】手机键盘的按键时间
#include <iostream>
#include <cstdio>
using namespace std;//c++全局命名空间
int keytab[26]={1,2,3,1,2,3,1,2,3,1,2,3,1,
2,3,1,2,3,4,1,2,3,1,2,3,4};
int main(){
string str;//c++才有字符串
while(cin >> str){//注意字符串输入格式
int time = 0;
for(int i = 0 ;i<str.size();i++){
time += keytab[str[i] - 'a'];
if((i != 0)&&(keytab[str[i]-'a']-keytab[str[i-1]-'a'] == str[i] - str[i-1])){
//同组等待
time+=2;
}
}
printf("%d\n",time);
}
return 0;
}
第三章 排序与查找
3.1 排序
sort函数:first起始位置,last终止位置,comp比较函数(默认从小到大排序)
排序:1.内定义数据类型 。 2.自定义数据类型。
排序算法的特性:
线性排序—计数排序
逆序数对(一个序列中前面的数大于后面的数,称他为逆序数)—归并排序
第K大数—快速排序
线性排序:O(nlogn)(下限) ---- 基于比较
O(n) ----给定范围
3.1.1 排序【例题3.1】
题目:对输入的n个数进行排序并输出
输入:输入的第一行包括一个整数n。接下来的一行包括n个整数。
输出:可能有多组测试数据,对于每组数据,输出排序后的n个整数,每个数后面都有一个空格。每组测试数据的结果占一行。
样例输入:
4
1 4 3 2
样例输出:
1 2 3 4
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int arr[100];
int main(){
int n;
while(scanf("%d",&n) != EOF){
for(int i = 0;i < n ;i++){
scanf("%d",&arr[i]);
}
sort(arr,arr+n);//默认升序排列
for(int i = 0 ; i < n ;i++){
printf("%d ",arr[i]);
}
}
return 0;
}
3.1.2 排序【例题3.2】成绩排序
#include <iostream>
#include <cstdio>
#include <algorithm>//算法包
using namespace std;
struct Student{//定义学生类
int number;
int score;
};
Student arr[100];//结构体数组
bool compare(Student x,Student y){//自定义sort的compare方法
if(x.score==y.score){
return x.number<y.number;//如果成绩相同,学号小的在前
}else return x.score<y.score;//成绩升序排序
}
int main(){
int n ;
scanf("%d",&n);
for(int i = 0 ;i < n; i++){
scanf("%d%d",&arr[i].number,&arr[i].score);
}
sort(arr,arr+n,compare);//sort(开始地址,结束地址,排序方法)
for(int i = 0 ;i < n;i++){
printf("%d %d\n",arr[i].number,arr[i].score);
}
return 0;
}
3.1.3 排序【习题3.2】整数奇偶排序
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int arr[10];
bool compare(int x,int y){//x,y有四种奇偶可能,找到内部的排序关系
if(x%2==1 && y%2==1){
return x<y;
}else if(x%2==0 && y%2==0){
return x<y;
}else if(x%2==1 && y%2==0){
return true;//x就是应该在y的前面
}else if(x%2==0 && y%2==1){
return false;//x不应该在y的前面
}
}
int main(){
while(scanf("%d",&arr[0]) != EOF){//多组输入,当第一个数存在时,继续输入给数组
for(int i = 1;i<10;i++){
scanf("%d",&arr[i]);
}
sort(arr,arr + 10,compare);
for(int i = 0; i<10;i++){
printf("%d ",arr[i]);
}
printf("\n");
}
return 0;
}
3.1.4 排序(4)前m大的数
给n个整数,按从小到大的顺序输出其中前m大的数。
/*
* 给n个整数,按从小到大的顺序输出其中前m大的数
* input:第一行有两个数n,m(0<n,m<1000000),第二行包含n个各不相同,且都处于区间[-500000,500000]的整数
* output:对每组测试数据按从小到大的顺序输出前m大的数
* 样例输入:
* 5 3
* 3 -35 92 213 -644
* 样例输出:
* 213 92 3
*/
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 1e6 + 10;//const静态变量。1e6=1*10^6
const int R = 5e5;//5e5=5*10^5
int arr[MAXN];//存储数字
int number[MAXN];//辅助数组,记录出现的次数,类似哈希表
int main(){
int n,m;
while(scanf("%d%d",&n,&m) != EOF){
memset(number,0,sizeof(number));//数组全部赋值0或-1,在cstring类中
for(int i = 0; i < n ; i++){
scanf("%d",&arr[i]);
number[arr[i] + R]++;//数字是辅助数组的下标(因为下标没有负数,所以平移)
}
//数组排序
int index = 0;
for(int i = 0;i<MAXN;i++) {//遍历辅助数组number
while(number[i]--){//出现的次数,可能有多次,也有可能不出现,则i跳过,但index不增加
arr[index++] = i - R;//更新数字,index指向的是arr数组的下标
}
}
//从后向前打印m个大数
for(int i = n-1;i>=n-m;i--){
if(i == n-m){
printf("%d\n",arr[i]);
}else{
printf("%d ",arr[i]);
}
}
}
return 0;
}
3.1.5 排序(5)归并排序:输出逆序对
代码1:【归并排序】
/*
* 归并排序:一直切一半分成两段,最终每段只有一个数字,视为有序。再两两按大小有序合并。
* 题目:第一行输入待排序数的个数,第二行输入待排序的数,输出按从小到大排序的数。
*/
#include <iostream>
#include <cstdio>
using namespace std;
const int nmax=100;
int arr[nmax];
int temp[nmax];
/* 连接函数:设置临时数组接收有序的合并数列。
* 三指针i,j,k,i和j比大小,小则放入temp[k]
* 某段剩余则全放入temp
* 最后将temp存回arr数组
*/
void Combine(int left,int middle,int right){
int i = left;//i指向左段第一个将比较数字
int j = middle + 1;//j指向右段第一个数字
int k = left;//k用来表明temp待存位置
while(i<=middle && j<=right){//是并且&&,i和j同时没有到头,则比较
if(arr[i] <= arr[j]){
temp[k++] = arr[i++];
}else{
temp[k++] = arr[j++];
}
}
while(i<=middle){
temp[k++] = arr[i++];
}
while(j<=right){
temp[k++] = arr[j++];
}
for(int k = left; k <= right;k++){
arr[k] = temp[k];
}
return;
}
void MergeSort(int left,int right){
if(left<right){//这一段有一个整数以上,还能拆
int middle = left + ( right - left )/2;//为了防止left+right溢出
MergeSort(left,middle);//拆分左段
MergeSort(middle+1,right);//拆分右段
Combine(left,middle,right);//假设要合并的两段已经有序
}
return;
}
int main(){
int n;
scanf("%d",&n);
for(int i = 0; i < n;i++){
scanf("%d",&arr[i]);
}
MergeSort(0,n-1);
for(int i = 0 ; i<n;i++){
printf("%d ",arr[i]);
}
return 0;
}
题目:POJ1804 逆序对数
/*
* 归并排序:一直切一半分成两段,最终每段只有一个数字,视为有序。再两两按大小有序合并。
* 题目:多组输入,第一行输入组数,从第二行开始,先输入待排序的数的个数,同一行后面输入待排序数。
* 输出:每组的逆序数。
* 逆序对数:左大右小的数对的个数。已知左右两段都有序,若arr[i]>arr[j],则左段i后所有数都大于arr[j]
* 则逆序数对为(middle-i+1)
*/
#include <iostream>
#include <cstdio>
using namespace std;
const int nmax=1010;
int arr[nmax];
int temp[nmax];
int number;//整个序列最终的逆序对数
/* 连接函数:设置临时数组接收有序的合并数列。
* 三指针i,j,k,i和j比大小,小则放入temp[k]
* 某段剩余则全放入temp
* 最后将temp存回arr数组
*/
void Combine(int left,int middle,int right){
int i = left;//i指向左段第一个将比较数字
int j = middle + 1;//j指向右段第一个数字
int k = left;//k用来表明temp待存位置
while(i<=middle && j<=right){//是并且&&,i和j同时没有到头,则比较
if(arr[i] <= arr[j]){
temp[k++] = arr[i++];
}else{
number += middle - i + 1;//对于一个arr[j]来说,有middle-i+1个逆序对
temp[k++] = arr[j++];
}
}
while(i<=middle){
temp[k++] = arr[i++];
}
while(j<=right){
temp[k++] = arr[j++];
}
for(int k = left; k <= right;k++){
arr[k] = temp[k];
}
return;
}
void MergeSort(int left,int right) {
if (left < right) {//这一段有一个整数以上,还能拆
int middle = left + (right - left) / 2;//为了防止left+right溢出
MergeSort(left, middle);//拆分左段
MergeSort(middle + 1, right);//拆分右段
Combine(left, middle, right);//假设要合并的两段已经有序
}
return;
}
int main(){
int caseNumber;//caseNumber组数
scanf("%d",&caseNumber);
for(int current = 1;current <= caseNumber;current++){
int n;
scanf("%d",&n);
for(int i = 0; i <n;i++) {//当前组的组号current
scanf("%d", &arr[i]);
}
number=0;
MergeSort(0,n-1);
printf("组号:%d",current);
printf("逆序对数:%d\n\n",number);
}
return 0;
}
4
4 2 8 0 3
10 0 1 2 3 4 5 6 7 8 9
6 -42 23 6 28 -100 65537
5 0 0 0 0 0
3.1.6 排序(6)快速排序:第k大数
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
int arr[100];
int partition(int left,int right){
int random = round(1.0*rand()/RAND_MAX*(right - left)+left);
swap(arr[left],arr[random] );
while(left < right) {
while (left < right && arr[right] >= arr[left]){
--right;
}
swap(arr[left] ,arr[right]);
while (left < right && arr[left] <= arr[right]){
++left;
}
swap(arr[left] ,arr[right]);
}
return left;
}
int Quicksort(int left,int right,int k){
int pos = partition(left,right);
if(pos == k-1){
return arr[pos];
}else if(pos < k-1){
return Quicksort(pos+1,right,k);
}else{
return Quicksort(left,pos-1,k);
}
}
int main(){
int n,k;
scanf("%d",&n);
for(int i = 0;i<n;i++){
scanf("%d",&arr[i]);
}
scanf("%d",&k);
int q = Quicksort(0,n-1,k);
printf("%d\n",q);
return 0;
}
3.2 查找
3.2.1 顺序查找-O(n)
3.2.2-3 二分查找-O(logn)
(1)自定义
(2)系统自带:
lower_bound:返回大于或等于目标值的第一个位置
upper_bound:返回大于目标值的第一个位置
散列查找-O(1)
3.2.2 二分查找
#include <iostream>
#include <cstdio>
#include <stdio.h>
#include <algorithm>
using namespace std;
int fun(int a[],int n, int x){
int left = 0;
int right = n-1;
while(left<=right) {
int mid;
mid = left + (right - left) / 2;
if (x == a[mid]) {
return 1;
} else if (x < a[mid]) {
right=mid-1;
} else if (x > a[mid]) {
left=mid+1;
}
}
return 0;
}
bool cmp(int a,int b){
return a<b;
}
int main(){
int n;
while(scanf("%d",&n) != EOF){
int a[n];
for(int i = 0;i < n ;i++){
scanf("%d",&a[i]);
}
sort(a,a+n);
int x,flag=0;
scanf("%d",&x);
flag= fun(a,n, x);
if(flag == 0){
printf("no\n");
}else{
printf("yes\n");
}
}
return 0;
}
第四章 字符串
4.1 字符串
4.2 字符串处理
4.2.1 字符串遍历:特殊乘法
#include <string>
#include <iostream>
#include <cstdio>
using namespace std;
int main(){
string a,b;
int sum =0;
cin >> a >> b;
for(int i = 0;i < a.size();i++){
for(int j = 0;j<b.size();j++){
sum += (a[i]-'0')*(b[j]-'0');
}
}
cout << sum <<endl;
return 0;
}
4.2.2 字符串加密
#include <iostream>
#include <cstdio>
#include <string>
using namespace std;
int main(){
string str;
while(getline(cin,str)){
for(int i = 0;i<str.size();i++){
if(str[i]>='a'&&str[i]<='z'){
str[i] = (str[i]-'a'+1)%26 + 'a';//别忘了还要再加上起始
}else if(str[i]>='A'&&str[i]<='Z'){
str[i] = (str[i]-'A'+1)%26 + 'A';
}
}
cout << str << endl;
}
return 0;
}
简单密码
#include <iostream>
#include <cstdio>
#include <string>
#include <string.h>
using namespace std;
int main(){
string str;
while(getline(cin,str)){
if("ENDOFINPUT"==str){
break;
}
getline(cin,str);
for(int i=0;i<str.size();i++){
if(str[i]>='A'&&str[i]<='Z'){
str[i]=(str[i]-'A'+21)%26+'A';
}
}
cout << str << endl;
getline(cin,str);
}
return 0;
}
4.2.3 字符串统计
#include <iostream>
#include <cstdio>
#include <string>
#include <string.h>
using namespace std;
int main(){
string str1,str2;
while(getline(cin,str1)){
if(str1 == "#"){
break;
}
getline(cin,str2);
int num[130];
memset(num,0,sizeof(num));
for(int n : str2){
num[n]++;
}
for(char i : str1){
printf("%c %d\n",i,num[i]);
}
getline(cin,str1);
}
return 0;
}
【例题4.5】字母统计
#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
#define max 10000
int main(){
char str[max];
int num[128];
memset(num,0,sizeof(num));
while(gets(str)){
for(int i = 0;i<strlen(str);i++){
if(str[i]>='A'&&str[i]<='Z'){
num[str[i]]++;
}
}
for(int i = 'A';i<='Z';i++){
printf("%c:%d\n",i,num[i]);
}
}
return 0;
}
4.3 字符串匹配
4.3.2 字符串匹配(2):数字模式串在数字文本串第一次出现的位置KMP
#include <iostream>
#include <cstdio>
using namespace std;
const int MAXN=1000000;
const int MAXM=10000;
int text[MAXN];
int pattern[MAXM];
int nexttable[MAXN];
void getNext(int s[],int len) {
int j = -1;
nexttable[0] = -1;
for (int i = 1; i < len; i++) {
while (j != -1 && s[i] != s[j + 1]) {
j = nexttable[j];
}
if (s[i] == s[j + 1]) {
j++;
}
nexttable[i] = j;
}
}
int KMP(int n,int m){
getNext(pattern,m);
int j = -1;
for(int i =0;i<n;i++){
while(j!=-1&&text[i]!=pattern[j+1]){
j=nexttable[j];
}
if(text[i]==pattern[j+1]){
j++;
}
if(j==m-1){
return i-j+1;
}
}
return -1;
}
int main(){
int caseNumber,n,m;
scanf("%d",&caseNumber);
while(caseNumber--){
scanf("%d %d",&n,&m);
for(int i = 0;i<n;i++){
scanf("%d",&text[i]);
}
for(int i = 0; i<m;i++){
scanf("%d",&pattern[i]);
}
printf("%d\n",KMP(n,m));
}
return 0;
}
4.3.2 字符串匹配(2):模式串在文本串中出现的次数
#include <iostream>
#include <cstdio>
using namespace std;
const int MAXN=1000000;
const int MAXM=10000;
char text[MAXN];
char pattern[MAXM];
int nexttable[MAXN];
void getNext(char s[],int len) {
int j = -1;
nexttable[0] = -1;
for (int i = 1; i < len; i++) {
while (j != -1 && s[i] != s[j + 1]) {
j = nexttable[j];
}
if (s[i] == s[j + 1]) {
j++;
}
nexttable[i] = j;
}
}
int KMP(char text[],char pattern[]){
int n = strlen(text),m=strlen(pattern);
getNext(pattern,m);
int j = -1,ans=0;
for(int i =0;i<n;i++){
while(j!=-1&&text[i]!=pattern[j+1]){
j=nexttable[j];
}
if(text[i]==pattern[j+1]){
j++;
}
if(j==m-1){
ans++;
j=nexttable[j];
}
}
return ans;
}
int main(){
int num;
scanf("%d",&num);
while(num--){
scanf("%s", pattern);
scanf("%s",text);
printf("%d\n", KMP(text, pattern));
}
return 0;
}