目录
模拟
#include <bits/stdc++.h>
using namespace std;
int s2i(string s) //string 转换为int
{
int res=0;
for(const auto & i:s)
res= res*10+i -'0';
return res;
}
string i2s(int x,int w)//int 转换为指定位数的string
{
string res;
while(x) res+=(x%10)+'0',x/=10;
while(res.length()<w) res+='0';
reverse(res.begin(),res.end());
return res;
}
bool isLeapYear(int year)//判断闰年
{
return (year%4==0&&year%100!=0)||(year%400==0);
}
bool isok(int year,int month,int day)//判断日期是否合法
{
int days[]={0,31,28,31,30,31,30,31,31,30,31,30,31};
if(isLeapYear(year)) days[2]=29;//是否闰年
return day<=days[month];
}
bool isPa(string s)//是否回文
{
for(int i=0;i<s.length()/2;++i)
{
if(s[i]!=s[s.length()-1-i]) return false;
}
return true;
}
bool isPa2(string s)//是否为ABABBABA的回文
{
if(!isPa(s)) return false;
return s[0]==s[2]&&s[1]==s[3];// ?
}
int main()
{
string s; cin>>s;//substr(n,m),从n位置开始往后取m位
int year=s2i(s.substr(0,4)),month=s2i(s.substr(4,2)),day=s2i(s.substr(6,2));
bool ans1=false,ans2=false;//用于是否找到了答案
for(int i=year;i<=9999;++i)
{
for(int j=1;j<=12;++j)
{
if(i==year&&j<month) continue;
for( int k=1;k<=31;++k)
{
if(i==year&&j==month&&k<=day) continue;
if(!isok(i,j,k)) continue;
string date=i2s(i,4)+i2s(j,2)+i2s(k,2);//拼接字符
if(!ans1&&isPa(date))
{
cout << date<<'\n';
ans1=true;
}
if(!ans2&&isPa2(date))
{
cout << date<<'\n';
ans2=true;
}
}
}
}
return 0;
}
递归
递归指函数直接或间接调用自身的过程
递归和循环的比较
递归的特点:
1.直观、简洁、易于理解和实现。
2.适用于问题规模可以通过调用调用不断减小的情况。
3.可以处理复杂的数据结构和算法,如图的遍历和树。
4.存在栈溢出风险,因此递归层数不宜过深。
循环的特点:
1.直接控制流程,效率较高。
2.适用于问题规模没有明显的缩减,或者需要一定的迭代。
3.大部分的动态规划。
斐波那契数列:
//斐波那契数列
/*
f(1)=f(2)=1;f(n)=f(n-1)+f(n-2),结果对1e9+7取模
*/
#include <iostream>
using namespace std;
using ll = long long;
const int N = 1e5 + 9;
const ll p= 1e9 + 7;
ll dp[N];//带备忘录
int f(int x)
{
//计算过的就不再重复计算,时间复杂度为O(n)
if (dp[x]) return dp[x];
if (x <= 2) return 1;
return dp[x]=(f(x - 1) + f(x - 2)) % p;
}
int main()
{
int n; cin >> n;
for (int i = 1; i <= n; ++i) cout << f(i) << '\n';
return 0;
}
例题:
排序
冒泡排序
冒泡排序的思想是每次将最大的一下一下运到右边,然后将最右边这个确定下来,再来确定第二大的。
冒泡排序一般用双层循环实现。
选择排序
选择排序的思想和冒泡排序类似,是每次找出最大的然后直接放到右边对应位置,然后将最右边这个确定下来(而不是一个一个的交换)(同一个题,方法不同)
插入排序
插入排序是一种简单直观的排序算法,基本思想是将待排序的元素逐个插入到已经排序的序列的合适位置,使得已排序序列逐渐扩大,从而构成有序序列,最终得到完全有序的序列。类似打扑克的手牌。
例题
快速排序
快速排序是一种基于分治法的排序方法,原理是将一个数组分成两个子数组,其中一个子数组的所有元素都小于另一个子数组的元素,然后递归的对两个数组进行排序。
思想:不断的将数组分成两个子数组,递归的对子数组进行排序,最终得到一个有序的数组。
通过选择合适的基准和分区操作实现
时间复杂度:O(nlogn)
归并排序
原理是将一个数组分成两个子数组,将子数组向下递归的排序后(当数组中仅有一个元素值无需再排序,直接返回),得到两个有序数组,然后进行O(n)的合并,最终合并成有序的原数组。
两个有序数组合并成一个原数组,方法是依次对比两个数组的值,将较小的值放到数组中。
递归主体MergeSort();传入参数为要排序的数组和区间的左右端点。
注意:当区间为一时,直接返回。
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);
//排序完成后a[l,mid],a[mid+1,r]都是分别有序的
//将a[l,r]两部分一个个放入b[l,r]中
int pl = 1, pr = mid + 1, pb = l;
while (pl <= mid || pr <= r)
{
if (pl > mid)
{
//左半边已经放完
b[pb++] = a[pr++];
}
else if (pr > r)
{
//右半边已经放完
b[pb++] = a[pl++];
}
else
{
//两边都有元素,取小的放进去
if (a[pl] < a[pr]) b[pb++] = a[pl++];
else b[pb++] = a[pr++];
}
}
//完成后复制
for (int i = 1; i <= r; ++i) a[i] = b[i];
}