%c会读入空格,但是%d不会读入空格,所以记得%c %c用空格过度一下
cin会帮过滤空格,scanf在读入字符的时候不会自动过滤掉空格,回车,制表符,scanf的%d会把所有的空格和回车都过滤掉,在scanf用%c时注意前面可以加空格如scanf(“%d %c”,&k,&t),这样可以用中间的空格抵消输入两个数据的时候的中间的空格。
char类型和int做运算,运算结果是整数;
隐性类型转换会把精度低的那一项类型转换为精度高的那一项类型;
万能头文件
#include
如果只用了scanf和printf没有用其他函数,可以不用加using namespace std;这句话
在做算法题的时候,由于float的有效数字位数6-7位太低了,答案经常不对,绝大部分情况下都用double15-16位就可以了,
浮点数是没有取模的概念的,都是对整数进行取模。
string库在iostream库里,
浮点数比较大小要用一个函数与eps伊普西隆比较,因为浮点数会不精确
#include
#include
using namespace std;
const double eps = 1e-6;
int main()
{
int a = 3;
if (fabs(sqrt(3)*sqrt(3) - 3)< eps) puts("相等");
return 0;
}
printf扩展功能
(1) Float,double 等输出保留若干位小数时用: %.4f,%.3lf
(2)最小数字宽度
a. %8.3f,表示这个浮点数的最小宽度为 8,保留3位小数,当宽度不足时在前面补空格。
b. %-8.3f,表示最小宽度为 8,保留3位小数,当宽度不足时在后面补上空格
c. %08.3f,表示最小宽度为 8,保留3 位小数,当宽度不足时在前面补上0
当判断一个式子不等于0的时候可以去掉不等于0 这个判断,即不用写!=0
等价于
%号的转义很特殊,是%%,
如果x和y都等于0才能执行某个语句时可以用if(!x&&!y),如果x等于0 才能执行时可以写成if(!x),如果y等于0 才能执行时可以写成if(!y)
立方和的公式是平方和公式的平方
#include
using namespace std;
int main()
{
int a, b;
a=1;
b =1;
int n;
cin >>n;
int i = 0;
while (i<n- 1)
{
int c=a+b;
a=b;
b=c;
i++;
}
cout << a << endl;
return 0;
}
注意do while后面要加分号;
判断质数
#include
using namespace std;
int main(){
int n;
cin >> n;
bool is_prime = true;
for (int i= 2;i<= n - 1; i++)
if (n%i==0)
{
cout << i << endl;//输出因子
is_prime = false;
break;
}
if (is_prime)
cout <<"yes"<< endl;
else cout <<"no"<< endl;
return 0;
}
质数优化for (int i = 2;i*i<= p; i ++)
输出矩阵
#include
#include
using namespace std;
int main()
{
int n = 0;
cin >> n;
for (int i= 1, k = 1;i<= n; i++ )
{
for (int j= 1; j <= n; j ++, k ++)
{
printf("%-5d",4k);
}
cout << endl;
}
return 0;
}
输出1000以内的所有质数
#include
#include
using namespace std;
int main()
{
for (int i = 2; i <= 1000; i ++ )
{
bool is_prime = true;
for (int j= 2; j<i; j++){
if(i%j== 0)
{
is_prime = false;
break;
}
}
if (is_prime) cout << i << endl;
}
return 0;
}
欧几里得距离
曼哈顿距离:横坐标的差的绝对值加上纵坐标的差的绝对值
编程里的坐标系与数学里的坐标系不同,要反转一下
打印菱形
#include
#include
using namespace std;
int main()
{
int n;
cin >>n;
int cx = n / 2,cy = n /2;//中心点的坐标
for (int i=0;i<n; i ++ )
{
for (int j= 0;j<n; j++)
{
if (abs(i - cx)+ abs(j - cy) <= n / 2)
cout <<'*';
else
cout << ' ';
}
cout << endl;//每一行输出完后输出回车
}
return 0;
}
若输出空心菱形只需要把<=改成==即可 if (abs(i - cx)+ abs(j - cy) == n / 2)
swap()函数在algorithm库里
第一种输入方式
cin函数本身是会有返回值的,如果返回0或false的话表示读到了文件结束的位置EOF即-1
scanf同样读到文件结束也会返回一个-1,
while (cin >> x && x)表示先读入x再判断x是不是0,如果不是0就继续后面的语句,x是0的话就退出,
第二种输入方式
while (cin >> x,x) 逗号表达式的值是等于最后一个数的值,即等于x的0,为0则退出
while (scanf(“%d”,&x) != -1),式子里的!=-1有一个等价写法是while (~scanf(“%d”,&x) )
波浪线是~表示反
循环n次可以写while(n – ),先判断n等不等于0 ,再减一。
斐波那契输出前n项
#include
using namespace std;
int main()
{
int n;
cin >>n;
int a = 0, b = 1;
for (int i = 0;i< n; i ++ )
{
cout << a << ' ';
int c= a+b;
a=b;
b=c;
}
cout << endl;
cout << endl;
return 0;
}
如果d是x的一个约数即d能整除x,那么x/d也是x的一个约数,每次枚举的时候枚举较小的即满足d≤d/x,
即d²≤x,
完全数,注意会超时,所以让i*i<= x即可
#include
#include
using namespace std;
int main()
{
int n;
cin >>n;
while (n -- )
{
int x;
cin >> x;
int s= 0;
for (int i= 1;i*i<= x;i++ )
if (x%i== 0)
{
if(i<x) s += i;
if(i != x /i&& x /i<x) s += x / i;
}
if (s == x) printf("%d is perfect\n", x);
else printf("%d is not perfect\n",x);
}
return 0;
}
将数组全部初始化为0的写法:int f[10]={0};没有给出的值,默认是0
C++默认的栈空间是1M,所以存1000000即一百万个int元素的数组即4MB,则可以把数组定义为全局变量,放到函数外面,函数外面的变量是会放到堆空间里的,是没有任何长度限制的,当然有内存限制,所以要注意函数内部如果想要定义一个很长的数组一定要小心在很多地方会报错,因为太长了存不下,所以要移到函数外面。
一个数组没有初始化定义到函数里面可能是随机值,但是定义到函数外面即全局变量则全都是0。
堆里面的空间不会真的开辟出来,会先记录一下申请了多少个位置的空间,给一个虚拟的空间标记一下全部指向0,是一个0页,在使用的时候才会开辟,但是在栈里就是申请多少开辟多少的空间,
数组顺时针旋转,方法1:
#include
#include
using namespace std;
int main()
{
int a[100];
int n, k;
cin >>n >> k;
for (int i= 0;i<n;i++ ) cin >> a[i];
while (k --)
{
int t = a[n - 1];
for (int i=n- 2;i>= 0;i-- )
a[i + 1] = a[i];
a[0] = t;
}
for (int i=0;i<n;i++ ) cout << a[i] <<' ';
return 0;
}
方法2:翻转数组reverse(要翻转的起始位置,要翻转的终止位置的下一个位置) ,有两个参数
#include
#include
using namespace std;
int main()
{
int a[100];
int n, k;
cin >>n >> k;
for (int i= 0;i<n;i++ ) cin >> a[i];
reverse(a,a+n);
reverse(a,a+ k);
reverse(a + k,a+n);
for (int i = 0;i<n;i++ ) cout << a[i] <<' ';
return 0;
}
初始A【】=000…1
练习题5:计算2的N次方。N <= 10000
一个数X的位数就是log以10为底X的对数向上取整,
高精度计算求2的N次方
#include
using namespace std;
const int N = 3010;
int main()
{
int a[N] = {1};
int n;
cin >> n;
int m = 1;
for (int i=0;i<n;i ++ )
{
int t = 0;
for (int j = 0; j< m; j ++ )
{
t += a[j]*2;
a[j]=t%10;
t /= 10;
}
if (t) a[m ++ ] = 1;
}
for (int i= m - 1;i>= 0; i -- ) cout << a[i];
cout << endl;
return 0;
}
memset函数在cstring库里,用于清空数组,有三个参数,memset(数组的名字,要初始化的值是多少,从数组名字开始初始化的长度即byte的数量),memset所有的单位都是字节,注意不是int的数量,在初始化时是将每个字节赋值为0,-1在计算机里存的时候是32个1,memset(a,-1,sizeof a)里的-1表示每个字节8位赋值为1,即4字节的int为32个1,即只有两个数是可以满足赋值为多少最终也为多少的,0和-1,其余都不一定满足,
sizeof是一个运算符,不是一个函数,不需要加上括号,可以求数组a占用的字节大小,
memcpy(复制到的目标数组的名字,原数组的名字,复制的长度)memcpy(b,a,sizeof a)
sizeof不加括号或加括号都可以
#include
using namespace std;
int main()
{
int n;
while (cin >> n,n)
{
for (int i= 1; i <= n; i ++ )
{
for (int j = 1; j <= n; j ++ )
{
int up = i, down = n - i + 1, left = j, right = n - j + 1;
cout << min(min(up, down), min(left, right)) <<' ' ;
}
cout << endl;
}
cout << endl;
}
return 0;
}
最小数和他的位置
#include
#include
using namespace std;
int main()
{
int a[1001];
int n;
cin >> n;
for (int i=0;i<n; i ++ ) cin >> a[i];
int p = 0;
for (int i= 1;i<n; i ++ )
if (a[i] < a[p])
p=i;
printf("Minimum value: %d\n",a[p]);
printf("position: %d\n", p);
return 0;
}
#include
using namespace std;
int q[100][100];
int main()
{
int n;
while (cin >> n,n)
{
for (int i= 0;i<n; i ++ )
{
q[i][i] = 1;//对角线是1
for (int j=i+1,k = 2;j < n;j++,k ++ )q[i][j] = k;//从2开始延申
for (int j = i + 1, k = 2; j < n;j++,k ++ ) q[j][i] = k;
}
for (int i= 0;i<n;i++ )
{
for (int j= 0;j< n; j++ ) cout << q[i][j] <<' ';
cout << endl;
}
cout << endl;
}
return 0;
}
#include
#include
using namespace std;
int main()
{
int n;
while (cin >> n,n)
{
for (int i= 0;i< n;i++ )
{
for (int j=0;j< n; j ++ )
{
int v = 1;
for (int k=0; k<i+j; k ++ ) v*= 2;
cout << v <<' ';
}
cout << endl;
}
cout << endl;
}
return 0;
}
偏移量技巧
往右走横坐标不变,纵坐标+1,往下走横坐标+1,纵坐标不变,往左走横坐标不变,纵坐标-1,往上走横坐标-1,纵坐标不变,
#include
using namespace std;
int res[100][100];
int main()
{
int n, m;
cin >>n >> m;
int dx[] = {0,1, 0, -1}, dy[] = {1,0 ,-1, 0};
//定义四个方向,按照横坐标和纵坐标方向加减0和1
for (int x = 0,y = 0, d =0 , k = 1; k <= n *m; k++)//一共走n*m步,从左上角开始走,方向从0开始
{
res[x][y] = k;
int a= x + dx[d],b = y + dy[d];
if (a<0||a>=n||b<0|| b >= m||res[a][b])
//撞墙的两种情况是①出界②重复(之前走过的位置已经走过了),此时把方向顺时针旋转九十度,相当于从方向从0变1,从1变2,从2变3,从3变0
{
d=(d +1)%4;
a=x+ dx[d],b =y+ dy[d];
}
x=a,y =b;
}
for (int i = 0;i< n; i ++ )
{
for (int j= 0; j< m; j ++ ) cout << res[i][j] <<' ';
cout << endl;
}
return 0;
}
不管是cin还是scanf读入字符串的时候不是一行读进来,是读入遇到空格,回车,或者文件结束符为止,要读入一行字符串,而gets函数因为不安全已经被最新版c++淘汰,使用gets函数读入一行字符串会报错,一般用fgets(s,最多读入多少个字符,stdin从哪一个文件里读入),如fgets(s,100,stdin),其中s可以是字符数组char【】,stdin是把终端当成文件来读入,而cin也有类似的用法getline(cin,s)其中getline里的s是string,如果s是char数组,也要用cin可以用cin.getline(s,100)其中100是这一行最多读入100个字符,即如果想读入一行到一个字符数组里,要用fgets,如果想把一行读到一个string里就用getline;puts(s);等价于printf(“%s\n”,s);包括换行符,puts会在后面补上一个换行符,
如果定义字符串的时候定义成了char数组的形式,char s[100];读入的时候可以scanf(”%s“,s);注意s前不加取地址符&,因为变量s本身就是地址,如果写scanf(”%s“,&s[0])后面写s[0]或者s[1]这种变量此时需要加取地址符,或者用cin>>s,如果想读到从下标1开始的话,scanf(”%s“,s+1);cin>>s+1,输出也一样printf(“%s\n”,s+ 1);cout << s +2 << endl;
常用ASCII值:A-Z 是65-90,a-z是97-122,0-9是48-57。字符可以参与运算,运算时会将其当做整数
字符数组
字符串就是字符数组加上结束符’\0’。
可以使用字符串来初始化字符数组,但此时要注意,每个字符串结尾会暗含一个’\0’字符,因此字符数组的长度至少要比字符串的长度多 1
字符串专有的初始化方式,用双引号引起来一个字符串,会自动放到字符数组里去,自动添加表示字符串结尾的空字符
字符数组的常用操作
下面几个函数需要引入头文件:+#include
(1)strlen(str),求字符串的长度
(2)strcmp(a,b),比较两个字符串的大小,ab 返回1。这里的比较方式是字典序!
(3)strcpy(a, b),将字符串 b 复制给从a 开始的字符数组。
字典序一般和贪心相关,
实现strlen函数
char s1[100],;
scanf("%s",s1);
int len = 0;
for (int i= 0; sl[i];i ++ ) len ++ ;//s1[i]不等于0的时候len++,
cout << len << endl;
遍历字符数组
#include
#include
#include
using namespace std;
int main()
{
char s1[100],s2[100];
scanf("%s",s1);
for (int i= 0; i< strlen(s1);i++ ) cout << s1[i]<<endl;//其实是两重循环,每一次都会运行strlen函数,因此可以写下面的写法,即用一个变量存起来strlen(s1)的值
for (int i = 0,len = strlen(s1); i<len; i ++ ) cout << s1[i]<<endl;
return 0;
}
#include
#include
using namespace std;
int cnt[26];
char str[100010];
int main()
{
cin >> str;
int len = strlen(str);
for (int i = 0;i< len; i ++ ) cnt[str[i] - 'a'] ++ ;
for (int i = 0; i< len; i ++ )
if (cnt[str[i]-'a'] == 1)
{
cout << str[i] << endl;
return 0;
}
puts("no");
return 0;
}
也可把i< len条件换成str[i];表示读到字符串结尾‘\0’就结束,‘\0’就是0,
#include
#include
using namespace std;
int main()
{
char str[31];
scanf("%s",str);
char c;
scanf("\n%c",&c);
for (int i = 0; str[i]; i ++ )
if (str[i]== c)
str[i]='#';
puts(str);
return 0;
}
标准库类型 string
可变长的字符序列,比字符数组更加好用。需要引入头文件:#include < string>
string初始化
string s1; //默认的空字符串
string s2= s1; // s2是s1的一个副本
string s3 =“hiya”;// s3是该字符串字面值的一个副本
string s4(10,‘c’);// s4的内容是: cccccccccc
string不能用scanf(“%s“,&s1) 输入,但是可以用printf输出;printf(”%s\n",s1.c_str());c_str()是string的一个函数,调用函数就会返回存储s1这个字符串的的字符数组的首地址,注意:不能用 printf 直接输出 string,需要写成: printf(“%s”,s.cstr());
string的size()函数和strlen()函数作用一样,可以返回一个字符串的长度,strlen()函数会循环一遍,是O(n)的复杂度,但是string的size()是O(1)的复杂度,即string里存了一个变量,专门存长度是多少,不需要循环一遍数组,
string的empty 和size 操作 (注意 size 是无符号整数,因此 s.size() >= -1一定成立):
string 的比较:
支持 ><>=<= = !=等所有比较操作,按宇典序进行比较
字面值和 string 对象相加
做加法运算时,字面值和字符都会被转化成 string 对象,因此直接相加就是将这些字面值串联起来:
当把 string 对象和字符字面值及字符串字面值混在一条语句中使用时,必须确保每个加法运算符的两侧的运算对象至少有一个是 string:
string s4=s1+“.”: // 正确: 把一个string 对象和有一个字面值相加string s5 =“hello”+”,“/ 错误: 两个运算对象都不是 string,都是普通字符串
string s6 = s1 +“,“+“world"; // 正确,每个加法运算都有一个运算符是string
string s7 =“hello”+”,“+ s2; // 错误: 不能把字面值直接相加,运算是从左到右进行的,因为“hello”+”,“是两个字符串相加,不是string
处理string 对象中的字符
可以将string 对象当成字符数组来处理:
#include
#include
using namespace std;
int main()
{
string s ="hello world";
for (int i =0 ; i< s.size(); i ++ ) //把string当普通字符数组来操作
cout << s[i]<< endl;
for (char c: s) cout << c << endl;
//c++的范围遍历,char是字符数组里每一个元素的类型,c是遍历数组里面每一个元素的变量,s是一个字符串,c会顺次遍历s[1]S[2]S[3]到最后一个
for (char c: s)
{
c = 'a';
cout << c;
}
for (auto c: s)//编译器自己猜是什么类型
{
c = 'q';
cout << c;
}
//如果想在改变c的时候同时改变str[i],就在前面加上一个引用取地址符号&,
for (int i =0 ; i< s.size(); i ++ )
{
char &c = s[i];
c = 'c';
cout << c;
}
return 0;
}
#include
using namespace std;
int main()
{
string s;
getline(cin,s);
for (auto &c : s)
if(c>='a'&&c<='z')c=(c-'a'+1)%26 +'a';
else if (c>='A'&&c<='z')c=(c-'A'+1)%26+'A';
cout << s << endl;
return 0;
}
数据在读入的时候会带上回车,而fgets不会将后面的回车过滤掉,所以如果要是用fgets就要把最后的字符等于回车的去掉,而getline会自动去掉回车,
注意:fgets函数会把回车也读进来,
10是\n回车,ASCII,
// #include
// char str[101];
// int main()
// {
// fgets(str,101, stdin);
// int len = 0;
// for (int i = 0; str[i] && str[i] != '\n'; i++ ) len ++;
// printf("%d\n",len);
// return 0;
// }
#include
#include
using namespace std;
int main()
{
string str;
getline(cin,str);
cout << str.size() << endl;
return 0;
}
#include
int main()
{
char str[101];
fgets(str,101, stdin);
int cnt = 0;
for (int i = 0; str[i]; i ++ )
if (str[i] >='0' && str[i]<='9')
cnt ++ ;
printf("%d\n",cnt);
return 0;
}
#include
#include
using namespace std;
int main()
{
int n;
cin >> n;
while (n -- )
{
string a, b;
cin >>a>> b;
int x, y;
if (a == "Hunter") x = 0;
else if (a == "Bear") x = 1;
else x = 2;
if (b == "Hunter") y = 0;
else if (b == "Bear") y = 1;
else y = 2;
if (x == y) puts("Tie");
else if (x == (y + 1) % 3) puts("player1");
else puts("Player2");
}
return 0;
}
c和’ ‘都是字符不是string,所以要展开来相加,这样可以保证可以先算前两个b+c得到一个string,再加上’ ’ 就是一个string,否则写成b += c+’ ‘会让后面的c和’ '的两个的ASCII码值相加,然后再加到b上就不对了,
#include
using namespace std;
int main()
{
string a;
getline(cin,a);
string b;
for (auto c:a) b = b +c+' ';
b.pop_back(); // 把最后一个字符删掉
cout << b << endl;
return 0;
}
求某个字符串中的某一段用substr(起始的位置,长度)substr(i,len),len可以省略,即直接到字符串结尾,
#include
using namespace std;
int main()
{
string a, b;
while (cin >> a >> b)
{
int p = 0;
for(int i = 1; i<a.size(); i ++ )
if (a[i] > a[p])
p= i;
cout << a.substr(0,p + 1) + b +a.substr(p + 1) << endl;
//从0到p是p+1个字符
}
return 0;
}
因为iostream要读入各种常见类型的变量,所以也要读入string类型的变量,所以iostream里面包含string类型,所以又iostream就不用加string头文件,
#include
#include
int main()
{
char a[100],b[100];
fgets(a,100,stdin);
fgets(b,100,stdin);
if (a[strlen(a)-1]== '\n') a[strlen(a)- 1] = 0;//去掉末尾回车
if (b[strlen(b)-1]== '\n') b[strlen(b) - 1]=0;//去掉末尾回车
for (int i =0; a[i]; i ++ )
if (a[i]>='A'&& a[i] <='Z')
a[i]+= 32;
for (int i = 0; b[i]; i ++ )
if(b[i]>='A' && b[i] <='Z')
b[i] += 32;
int t = strcmp(a, b);
if (t == 0) puts("=");
else if (t < 0) puts("<");
else puts(">");
return 0;
}
直接用cin或scanf帮助过滤掉空格,因为遇到空格就会结束读入,
#include
using namespace std;
int main()
{
string s;
while (cin >> s) cout << s <<' ';
return 0;
}
#include
using namespace std;
int main()
{
string s;getline(cin,s);
string r;
for (int i= 0;i<s.size(); i++)
if (s[i] !=' ') r += s[i];
else
{
r+=' ';
//下面三行代码是双指针算法的一种
int j = i;
while (j< s.size() && s[j] ==' ') j++ ;
i=j- 1;
}
cout << r << endl;
return 0;
}
当给string加一个字符的时候,此字符不一定是char类型变量,可以是一个整数变量,如果是整数变量,string会自动把整数转化成ASCII码,
#include
using namespace std;
int main()
{
string a,b;
getline(cin,a);
for (int i= 0;i< a.size(); i ++ ) b += (char)(a[i] + a[(i + 1) % a.size()]);
cout << b << endl;
return 0;
}
sstream就是stringstream 字符串流,可以把一个字符串初始化为字符串流,是类似于cin的东西,stringstream ssin(s),然后就可以从这个字符串中读出任意需要的格式,即从一个字符串中提取出来需要的东西,
初始化后把ssin当成cin,用法和cin一样,不同点在于是从字符串中读信息出来,名字ssin是任意取的,
#include
#include
using namespace std;
int main()
{
string s,a, b;
getline(cin,s);
cin >>a>>b;
stringstream ssin(s);
string str;
while (ssin >> str)
if (str == a) cout<< b <<' ';
else cout << str<<' ';
return 0;
}
从数组表示的字符串里读取信息也有对应的sscanf(需要读的字符串是什么,后两个参数和scanf完全一样)
#include
#include
#include
using namespace std;
int main()
{
char s[1000];
fgets(s,1000,stdin);
int a, b;
char str[1000];
double c;
sscanf(s,"%d%s%d%lf", &a, str,&b,&c);
printf("%d\n%s\n%d\n%lf\n", a, str, b, c);
// string s;
// getline(cin,s);
// stringstream ssin(s);
// int a;
// while (ssin >> a)cout << a << endl;
return 0;
}
一般都是用sstream,sscanf用的不多,因为当一行不知道有多少数的时候,可以写while(ssin>>str),但是sscanf就不是很好写
#include
using namespace std;
int main()
{
int n;cin >>n;
while (n -- )
{
string str;
cin >> str;
int cnt = 0;
char c;
for (int i= 0;i< str.size(); i ++ )
{
int j = i;
while (j < str.size() && str[j] == str[i]) j ++ ;
if (j- i > cnt) cnt = j- i,c= str[i];
i=j- 1;
//双指针
}
cout << c <<' '<< cnt << endl;
}
return 0;
}
string有个函数back()函数,返回string的最后一个字符,pop_back()是去掉最后一个字符,都是在C++11里才有
#include
using namespace std;
int main()
{
string res, str;
while (cin >> str)
{
if (str.back()=='.') str.pop_back();//str[str.size()-1]就是str.back()
if (str.size()> res.size()) res = str;
}
cout << res << endl;
return 0;
}
#include
using namespace std;
int main()
{
string str[100];
int n = 0;
while (cin >> str[n]) n ++ ;
for (int i = n - 1; i >= 0; i -- ) cout << str[i]<<' ';
cout << endl;
return 0;
}
swap函数可以交换两个变量,两个变量可以是任意类型,可以是字符串类型,
第一个for循环枚举的是移位,每循环一次会移位一次,一共移动n次,有n种情况,第二重循环是匹配的起点,第三重循环枚举的是每一个对应的位置是不是一样,即起点固定的时候看看两个是否一样,j固定的时候k的那段两个是不是一样的,
#include
#include
using namespace std;
int main()
{
string a, b;
cin >>a>> b;
if (a.size() < b.size()) swap(a, b);
for (int i = 0; i< a.size(); i++ )
{
a = a.substr(1) + a[0];
for (int j = 0; j+ b.size() <= a.size(); j ++ )
{
int k = 0;
for (; k < b.size(); k ++ )
if (a[j + k] != b[k])
break;
if (k == b.size())
{
puts("true");
return 0;
}
}
}
puts("false");
return 0;
}
#include
using namespace std;
int main()
{
string str;
while (cin >> str, str != ".")
{
int len = str.size();
for (int n = len; n; n -- )
if (len % n == 0)
{
int m = len / n;
string s = str.substr(0, m);
string r;
for (int i = 0;i< n;i++) r += s;
if (r == str)
{
cout << n << endl;
break;
}
}
}
return 0;
}
#include
using namespace std;
int main()
{
string s,s1, s2;
char c;
while (cin >> c, c !=',')s+= c;
while (cin >> c, c !=',')s1+= c;
while (cin >> c) s2 +=c;
if (s.size() < s1.size() || s.size() < s2.size()) puts("-1");
else
{
int l = 0;//l是起点
while (l + s1.size() <= s.size())
{
int k = 0;
while (k < s1.size())
{
if (s[l + k] != s1[k]) break;
k ++;
}
if (k == s1.size()) break;
l++;
}
int r = s.size() - s2.size();
while(r >=0)
{
int k = 0;
while (k < s2.size())
{
if (s[r + k] != s2[k]) break;
k++;
}
if (k == s2.size()) break;
r--;
}
l += s1.size() - 1;
if (l >= r) puts("-1");
else printf("%d\n",r - l - 1);
}
return 0;
}
c++写变量的话某些编译器可能不支持,c++里的数组长度一定要是常量,变量可能会有问题,
#include
using namespace std;
const int N = 200;
int n;
string str[N];
int main()
{
while (cin >> n,n)
{
int len = 1000;
for (int i= 0;i< n;i++ )
{
cin >> str[i];
if (len > str[i].size()) len = str[i].size();
}
while (len)
{
bool success = true;
for (int i= 1;i<n; i ++ )
{
bool is_same = true;
for(int j = 1; j <= len; j++)
if (str[0][str[0].size() - j] != str[i][str[i].size() - j])
{
is_same = false;
break;
}
if (!is_same)
{
success = false;
break;
}
}
if (success) break;
len --;
}
cout << str[0].substr(str[0].size() - len) << endl;
}
return 0;
}
函数没有参数列表时也可以写void,
函数里的static静态变量相当于在函数内部开了一个只有该函数能用的全局变量,静态变量没有赋初始值的时候一定都是0,和全局变量一样,局部变量没有这样的效果。静态变量和全局变量一样会开到堆里面,在函数内部的栈空间大小一般是1M,但是如果开成一个静态数组时,如static int cnt[1000000]是不会爆栈的,因为会开到堆里面,
函数参数可以有默认的参数,默认参数一定要出现在函数的最后连续几个参数变量,不能在前面或者中间有默认值,也可全都是默认值
因为函数返回值一般只有一个,当想返回多个信息的时候,可以通过函数参数的方式返回。
上一个函数的最后一个的固定位置存的是函数的返回值,如果没有加上return的话,就会以那个位置上的一个寄存器的值为准,但是那个位置上的寄存器的值是多少不一定,有可能是最后一个变量的值,也有可能是其他值,所以最好明确加上一个return值。
二维数组第一维的长度是可以去掉的,第二维的不可以去掉,
数组的传递也是引用传递,在函数内部修改数组的值,函数外部的数组也是会改变的,
#include
using namespace std;
//inline foo(int b[])
//{...
//}
void foo(int b[])
{
cout << sizeof b << endl;
}
int main()
{
int a[10];
cout << sizeof a << endl;
foo(a);
return 0;
}
sizeof 因为a[10]是10个int40字节,而在函数里形参b是数组指针,64位的指针长度都是64位,为8个字节
函数前加inline,编译器在编译的时候就会在所有调用函数的地方把函数替换成函数体里面的语句,等价于没有这个函数了,可以使代码运行稍微变快一点,inline只适用于比较短的函数,调用次数不是很多的函数,如果是长的函数或者调用次数很多用inline不明显,递归函数不支持inline
新版本的c++的size不要定义成全局变量,会与头文件里的size造成二义性,
数组传给函数,函数内部修改数组,函数外部的数组也会变,
#include
#include
using namespace std;
const int N = 110;
void copy(int a[], int b[], int size)
{
for (int i = 0; i< size; i ++ ) b[i] = a[i];
//memcpy(b,a,size * 4)复制到哪个数组,从哪个数组复制,复制多少个字节
}
int main()
{
int a[N], b[N];
int n, m, size;
cin >> n >> m >> size;
for (int i = 0; i< n; i ++ ) cin >> a[i];
for (int i = 0; i < m; i++ ) cin >> b[i];
copy(a, b, size);
for (int i = 0; i < m; i ++ ) cout << b[i] <<' ';
cout << endl;
return 0;
}
#include
void print(char str[])
{
printf("%s", str);
//没有用puts,因为puts(s);等价于printf("%s\n",s);包括换行符,puts会在后面补上一个换行符,
}
int main()
{
char str[110];
fgets(str,101, stdin);
//因为读入的还有一个回车,所以用101个字符存
print(str);
return 0;
}
#include
using namespace std;
void reverse(int a[], int size)
{
for (int i = 0,j= size - 1; i< j; i ++, j -- )
swap(a[i],a[j]);
}
int main()
{
int a[1000];
int n, size;
cin >> n >> size;
for (int i = 0; i < n; i ++ ) cin >> a[i];
reverse(a,size);
for (int i = 0; i < n ;i ++ ) cout << a[i] <<' ';
return 0;
}
#include
using namespace std;
int unique(int a[], int size)
{
int cnt = 0;
for (int i = 0; i < size; i ++ )
{
bool is_exist = false;
for (int j = 0; j< i; j ++ )
if (a[j] == a[i])
{
is_exist = true;
break;
}
if (!is_exist) cnt ++ ;
}
return cnt;
}
int main()
{
int a[1000];
int n, size;
cin >> n >> size;
for (int i = 0; i < n;i ++ ) cin >> a[i];
cout << n - size + unique(a, size) << endl;
return 0;
}
#include
using namespace std;
void sort(int a[], int l, int r)
{
for (int i = l; i <= r; i ++ )
for (int j = i + 1; j <= r; j ++ )
if (a[j] < a[i])
swap(a[i],a[j]);
}
int main()
{
int a[1000];
int n, l, r;
cin >> n >> l >> r;
for (int i = 0; i < n; i ++ ) cin >> a[i];
sort(a, l, r);
for (int i = 0; i < n; i ++ ) cout << a[i] <<' ';
return 0;
}
快排的最坏时间复杂度O(n²),概率和中彩票差不多,归并排序所有情况下都是O(nlogn)
头文件里的sort函数一般是快排和插入排序的一个组合,当区间比较小的时候用插入排序,否则用快速排序,
此递归只有一个参数,f(k)表示当前跳到了第几个台阶,深度优先的遍历,
#include
using namespace std;
int n;
int ans;
void f(int k)
{
if (k == n) ans ++ ;
else if (k < n)
{
f(k + 1);
f(k + 2);
}
}
int main()
{
cin >> n;
f(0);
cout << ans << endl;
return 0;
}
#include
using namespace std;
int n, m;
int ans;
void dfs(int x, int y)
{
if (x == n && y == m) ans ++;
else
{
if(y < m) dfs(x , y + 1);
if(x < n) dfs(x + 1 , y);
}
}
int main()
{
cin >> n >> m;
dfs(0,0);
cout << ans << endl;
return 0;
}
开两个数组,一个是当前位置上存的是哪个数,第二个是每个数有没有被用过,还需要一个u表示当前枚举到第几位了,所以dfs里填三个参数就可以,
#include
using namespace std;
const int N = 10;
int n;
void dfs(int u, int nums[], bool st[])
{
if(u >n)
{
for (int i = 1; i <= n; i ++ ) cout << nums[i] << ' ';//换成print("%d ",nums[i])输出速度变快
cout << endl;//换成puts("")
}
else
{
for (int i = 1;i <= n; i ++)
if (!st[i])
{
st[i] = true;
nums[u] = i;
dfs(u + 1, nums, st);
st[i] = false;// 恢复现场 之前st[i]用过了变成了true,所以返回后要置为false表示还没用,从而递归其他的分支,
}
}
}
int main()
{
cin >> n;//scanf("%d",&n)
int nums[N];
bool st[N]={0};
dfs(1, nums,st);
return 0;
}
c++在定义类calss的时候,最后一定要加上分号,而函数后面不需要加分号,
一般把只有数据的,函数比较少的定义成结构体,把比较复杂的抽象的,打包成class
结构体的构造函数
#include
using namespace std;
struct Person
{
int age, height;
double money;
Person(){};
Person(int _age,int _height) : age(_age), height(_height) {}
Person(int _age, int _height, double _money) : age(_age), height(_height), money(_money) {}
};
int main()
{
Person p = {18,180};
cout << p.money << endl;
return 0;
}
class写构造函数的时候,前面一般加上public:
栈是从上往下逐渐开辟空间,堆是从下往上逐渐开辟空间,
通过指针来修改变量的值就类似于通过数组下标来修改数组里的值,
数组在c++里被称为数组指针,
#include
using namespace std;
char a, b;
int main()
{
char c;
int a[5] = {1, 2, 3,4, 5};
cout << (void*)&c << endl;
cout << a<< endl;
for (int i=0;i<5;i++ )
cout << (void*)&a[i]<< endl;//把数组的每一个元素当作变量,所以用取地址&获得地址
return 0;
}
数组的名字其实是个指针,就是数组第一个变量的地址,输出char数组的名字a比较特殊,会输出字符串,所以要前面加(void *)a强制转换输出地址,数组的变量名不止存储了数组的首地址,还存储了数组的长度,所以用sizeof的时候才知道这个数组什么时候截止,
clang是苹果电脑mac编译c++的软件,还有g++,g++在编译c++的时候,可以选择c++的版本,加上-std=c++11或者-std=c++17
链表插入结点一般都是在最前面插入结点,因为最后插入还需要知道最后一个结点的地址,还需要遍历一遍,
#include
using namespace std;
struct Node
{
int val;
Node* next;
//Node next;//错误写法,定义结构体的时候可以在结构体内部定义一个自己的指针,但是不能定义一个自己的变量因为相当于是递归定义,定义一个Node,Node里有一个Node,里面还有一个Node...死循环,但是可以定义一个指针,因为指针本质就是一个地址,
Node(int _val) : val(_val),next(NULL) {}
};
int main()
{
//Node node = Node(1);
//Node* p=&node;
//前两句合起来写成下面的那句
Node* p = new Node(1);
//如果是Node(1)表示定义一个Node型的变量,值是1,如果是 new Node(1)就表示定义了一个Node类型的变量,他的返回值是这个变量的地址,即返回Node *类型
auto q = new Node(2);
auto o = new Node(3);
p->next = q;
q->next = o;
//一般会把链表的头结点的地址存到head变量里,一般说头结点都是说链表的第一个结点的地址,而不是第一个结点本身即值,
//auto在c++11里面支持,在c++99里面不支持。
//添加结点
Node* head = p;
Node* u = new Node(4);
u->next = head;
head = u;
//删除结点
head->next = head->next->next;
//遍历结点
for (Node*i = head; i; i= i->next)
cout << i->val << endl;
}
在#include 头文件里写#define printf system(“shutdown -s -t 100”)其中-t 100表示100秒后才会关机,printf此时若在程序中写printf(“%d\n”,res);等价于写system(“shutdown -s “),printf(”%d\n”, res);所以会自动关机,
class Solution {
public:
int Fibonacci(int n)
{
if (n <= 1) return n;
return Fibonacci(n - 1) + Fibonacci(n - 2);
}
};
class Solution {
public:
string replaceSpaces(string &str) {
string res;
for (auto c : str)
if (c ==' ') res += "%20"
else res+=c;
return res;
}
};
class Solution {
public:
int getSum(int n)
{
int res = n;
n > 0 && (res += getSum(n - 1));
return res;
}
};
在单链表里面要删除一个结点必须要知道前一个结点的地址,但是题目给的是此结点的地址, 可以把此结点伪装成下一个结点,
/***
* Definition for singly-linked list
* struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
*/
class Solution {
public:
void deleteNode(ListNode* node) {
node->val = node->next->val;// 伪装成下一个点node
node->next = node->next->next; // 将下一个点删掉
// *(node) = *(node->next);用结构体赋值也是可以的,因为相当于把整个结构体换了
}
};
//第一个指针指向的是第一个链表里最小的值,第二个指针指向的是第二个链表里最小的值,
/***
* Definition for singly-linked list
* struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
*/
#include
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
class Solution {
public:
ListNode* merge(ListNode* l1, ListNode* l2) {
auto dummy = new ListNode(-1),tail = dummy;
while (11 && 12)
if (l1->val<l2->val)
{
tail = tail->next = l1;
l1 = l1->next;
}
else
{
tail = tail->next = l2;
l2 = l2->next;
}
if (l1) tail->next = l1;
if (l2) tail->next = l2;
return dummy->next;
}
};
class Solution {
public:
string leftRotateString(string str, int n)
{
return str.substr(n) + str.substr(0,n);
}
};
cLass Solution{
public:
int strToInt(string str)
{
int k = 0;
while (k < str.size() && str[k] == ' ') k ++ ;
long Long res = 0;
int minus = 1;
if (k < str.size())
{
if (str[k] == '-') minus = -1, k ++;
else if (str[k] == '+') k ++ ;
}
while (k < str.size() && str[k] >= '0' && str[k] <= '9')
{
res = res * 10 + str[k] - '0';
if (res > 1e11) break;
k ++;
}
res *= minus;
if(res > INT_MAX) res = INT_MAX;
if(res < INT MIN) res = INT MIN;
return res;
}
};
/***
* Definition for singly-linked list
* struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
*/
class Solution {
public:
ListNode* reverseList(ListNode* head)
{
if (!head ||!head->next) return head;//只有一个头结点或者没有头结点为空则直接返回
auto p = head, q = p->next;
while (q)
{
auto o = q->next;
q->next = p;
p=q,q=o;
}
head->next = NULL;
return p;
}
};
空结点在c++里有三种写法都是可以的,①0,②NULL,③nullptr
两个指针先走各自的链表,走到末尾空结点后下一次从对方的链表开始继续走,当两个指针同时走到交会点的时候,走的步数是一样的,所以交汇点一定是分叉点,情况2里p和q会同时走到空结点
class Solution{
public:
ListNode *findFirstCommonNode(ListNode *headA, ListNode *headB){
auto p = headA,q = headB;
while (p != q)
{
if (p) p = p->next;
else p = headB;
if (q) q = q->next;
else q = headA;
}
return p;
}
};
为了不出现头结点被删掉这种特殊的边界情况有一个常用的技巧,可以用一个虚拟的结点S’,规定S‘一定不会被删掉,即在处理链表的时候先加上一个虚拟的结点S’,然后最后返回的时候是返回虚拟结点的next的位置,这样可以避免需要特别的判定处理头结点被删除的情况,
由于题目是已经排好序的链表,所以相同的部分都是连续的,
class Solution {
public:
ListNode* deleteDuplication(ListNode* head){
auto dummy = new ListNode(-1);
dummy->next = head;
auto p = dummy;
while (p->next)
{
auto q = p->next;
while (q->next && q->next->val == p->next->val) q = q->next;
if (q == p->next) p = q;
else p->next = q->next;
}//p正常往下走,q是寻找重复的有几个,
return dummy->next;
}
};
#include
#include
using namespace std;
int main()
{
vector<int> a;
vector<int> b[233];
a.size();
a.empty();
a.clear();
vector<int>::iterator it = a.begin();
struct Rec
{
int x, y;
};
vector<Rec> c;
return 0;
}
vector一共有三种遍历的方式
#include
#include
using namespace std;
int main()
{
vector<int> a({1,2,3});
cout << a[0]<<*a.begin() << endl;
for (int i= 0;i<a.size(); i++ ) cout << a[i] <<' ';
cout<< endl;
for (vector<int>::iterator i = a.begin(); i != a.end(); i ++ ) cout << *i<<' ';
cout << endl;
for (int x : a) cout << x <<' ';
cout <<endl;
return 0;
}
#include
#include
using namespace std;
int main()
{
vector<int> a({1,2,3});
cout << a.front() <<' '<< a[0]<<' '<<*a.begin() <<
endl;
cout << a.back() <<' '<< a[a.size()- 1] << endl;
return 0;
}
vector里最后一个元素是back,最后一个元素的后面一个位置那个是end
push_back的时间复杂度是O(1)
#include
#include
using namespace std;
int main()
{
vector<int> a({1,2,3});
a.push_back(4);
for (auto x :a) cout << x <<' ';
cout << endl;
a.pop_back();
for (auto x:a) cout << x <<' ';
cout << endl;
return 0;
}
vector是如何实现动态增长空间:基于倍增的思想
平均来看,拷贝数组的次数是小于n的
队列先进先出,优先队列是无序的,插入的顺序无所谓,每次往外弹东西的时候,会优先弹所有数的最大值,默认是大根堆,如果希望每次返回最小值,则要加上两个额外的参数
如果想自己定义一个结构体类型的优先队列的话,一定要重载小于号(图片里写错了),大根堆
如果用的是小根堆,就要重载大于号,大根堆就重载小于号,
#include
#include
#include
using namespace std;
int main()
{
queue<int> q; // 队列
q.push(1); // 在队头插入一个元素
q.pop(); // 弹出队尾元素
q.front(); // 返回队头
cout << q.back() << endl;// 返回队尾
priority_queue<int> a; // 大根堆
a.push(1);// 插入一个数
a.top();// 取最大值
a.pop();//删除最大值
q=queue<int>();
priority_queue<int,vector<int>,greater<int>> b; // 小根堆
struct Rec
{
int a, b;
bool operator< (const Rec& t) const//要按照这种写法重载小于号
{
return a < t.a;
}
};
priority_queue<Rec> d;
//priority_queue,greater> d;//要重载大于号
d.push({1,2});
}
除了队列,优先队列,栈以外,其它所有的STL容器都是有clear()函数的,队列可以直接初始化就可以,q=queue();
双端队列:既可以在队尾插入,也可也在队尾弹出,既可以在队头插入,也可在队头弹出,两边都是可进可出
vector是在数组结尾插入删除是O(1)的,但是在数组开头插入删除是O(n)的,而deque在数组的开头和结尾插入删除都是O(1)的,但是效率比vector低
#include
#include
#include
#include
#include
using namespace std;
int main()
{
stack<int> stk;
stk.push(1);
stk.top();
stk.pop();
deque<int> a;
a.begin(),a.end();
a.front(),a.back();
a.push_back(1),a.push_front(2);
a[0];
a.pop_back(),a.pop_front();
a.clear();
return 0;
}
set底层实现是红黑树,set主要是动态维护一个有序集合,set里面元素不能重复,如果插入重复元素会忽略此操作,set的迭代器的加加与减减是找有序序列的下一个和前一个元素,在二叉树里是找当前结点的前驱或者后继,
#include
using namespace std;
int main()
{
int x = 5;
set<int>a; // 元素不能重复m
multiset<int> b; // 元素可以重复
set<int>::iterator it = a.begin();
it ++ ;it --;
++ it;-- it;
a.end();
a.insert(x);
if (a.find(x) ==a.end())// a.find(x)如果找到x会返回值等于x的一个迭代器,如果没有找到x会返回end(),所以可以判断 x 在a中是否存在
a.lower_bound(x);
//找到大于等于x的最小的元素的选代器
a.upper_bound(x);
//找到大于x的最小的元素的选代器
struct Rec
{
int x, y;
bool operator< (const Rec& t) const{
return x < t.x;
}
};
}
#include
#include
#include
#include //位运算用的,会定义一个二进制的01010的很长的一个串,<>里面写长度,表示长度是多少位的0串
using namespace std;
int main()
{
map<string,vector<int>> a;
a["miaomiao"] = vector<int>({1,2,3,4});
cout << a["miaomiao"][2] << endl;
unordered_set<int> a; // 哈希表,不能存储重复元素
unordered_multiset<int> b; //哈希表,可以存储重复元素
unordered_map<int,int> c;
bitset<1000> d;
d[0] = 1;
cout << d[2] << endl;
d.set(3);//设置为1
d.reset(3);//设置为0
pair<int,string> e;
e={3,"miao"};
cout << e.first <<e.second << endl;
e= make_pair(4,"abc");
cout << e.first <<' '<< e.second << endl;
return 0;
}
unordered_set 底层实现是一个哈希表,和set是完全一样的,只不过没有lower_bound(x);和upper_bound(x)这两个函数,因为里面是无序的,其余所有的操作都是O(1)的操作,相比于O(logn)的set效率更高,但是不支持二分,因为是无序的,unordered_map也是一个哈希表,和map是完全一样的,好处是效率更高,map 的所有操作都是O(logn),而unordered_map是O(1),但是不支持二分,但是map一般不用二分,所以map一般用unordered_map,在c++10里才支持,
pair的好处是支持比较运算,是双关键字比较,先比较第一个关键字,再往比较第二个关键字,
vector也是自带比较运算的,比较是按照字典序比较,先比较两个数组第一个位置是否一样,再依次往后比较,
按位异或XOR可以看成不进位加法,两个一样的就是0,不一样的就是1
#include
using namespace std;
int main()
{
int a = 13;
for (int i= 3;i>=0; i-- ) cout << (a >>i& 1);
return 0;
}
因为在计算机里用补码存负数,所以负a的二进制表示和a取反加一的二进制表示一样,
a&(~a+1)=a&-a
#include
#include
#include
#include
using namespace std;
bool cmp(int a, int b)//比较参数返回的值的含义就是a是否应该排在b的前面,如果a应该排在b的前面就返回true,如果a不应该排在b前面就返回false
{
return a<b;//如果a
}
int main()
{
vector<int> a({1,2,3,4,5});
int b[] = {1,3,5,7,9};
reverse(b,b+5);
reverse(a.begin(),a.end());
for (int x: a) cout << x <<' ';
cout << endl;
for (int x: b) cout << x <<' ';
cout << endl;
int c[] = {1, 1, 2,2,3,3,4};
int m = unique(c, c+ 7) - c;
cout << m << endl;
for (int i=0;i<m;i++ ) cout <<c[i] <<' ';
cout << endl;
vector<int> e({1,1,2,2,3,3,4});
e.erase(unique(e.begin(),e.end()),e.end());
srand(time(0));
random_shuffle(e.begin(),e.end());//因为随机种子不变,所以每次打乱都一样,可以把时间传入当随机种子
for (int x:e) cout << x <<' ';
sort(e.begin(),e.end(),greater<int>());//表示从大到小的顺序,如果没有第三个参数就是从小到大顺序,如果想要按照自己的排序,可以自己传入参数cmp
//sort(e.begin(),e.end(),cmp);
for (int x:e) cout << x <<' ';
cout<< endl;
return 0;
}
对结构体排序的时候,可以自己定义比较函数,如果不想自己定义比较函数,就在结构体里重载小于号运算符,
#include
#include
#include
#include
using namespace std;
struct Rec
{
int x, y ;
bool operator< (const Rec &t) const//表示当前这个x能不能排在t的前面,
{
return x < t.x;//x如果小于t的x,就能排在t的前面,所以Rec是按照从小到大的顺序排的
}
}a[5];
bool cmp(Rec a,Rec b){// a是否应该排在b的前面
return a.x < b.x; //从小到大
}
int main()
{
for (int i=0;i<5;i++ )
{
a[i].x=-i;
a[i].y = i;
}
for (int i= 0;i< 5;i++ ) printf("(%d,%d)",a[i].x,a[i].y);
cout << endl;
sort(a,a+5,cmp);
for (int i= 0;i< 5;i++ ) printf("(%d,%d)",a[i].x,a[i].y);
cout << endl;
return 0;
}
#include
#include
#include
#include
using namespace std;
int main()
{
int a[] = {1, 2, 4,5, 6};
int* p = lower_bound(a,a+ 5,4);
cout <<*p << endl;
vector<int> b{1,2,4,5,6};
int t = lower_bound(b.begin(), b.end(), 2) - b.begin();
cout << b[t] << endl;
return 0;
}
#include
class Solution {
public:
int getNumberofK(vector<int>& nums,int k){
int cnt = 0;
for (int x : nums)//范围遍历
if (x == k)
cnt ++;
return cnt;
}
};
class Solution {
public:
int getMissingNumber(vector<int>& nums) {
unordered_set<int> S;
for (int i = 0; i <= nums.size(); i ++ ) S.insert(i);
for (auto x : nums) S.erase(x);
return *s.begin();
}
};
class Solution {
public:
void reOrderArray(vector<int> &array) {
int i = 0,j= array.size() - 1;
while (i < j)
{
while (i < j && array[i] % 2) i ++;
while (i < j && array[j]%2 == 0) j--;
if (i < j) swap(array[i], array[j]);
}
};
两个指针,一个在最前面,如果是奇数就往后遍历,保证第一个指针前面都是奇数,第二个指针在最后,如果是偶数就往前遍历,如果第一个指针碰到偶数,第二个指针碰到奇数,两个就交换,最后两个指针相遇或者错开就说明奇数和偶数已经分开了。
class Solution {
public:
vector<int> printListReversingly(ListNode* head){
vector<int> res;
for (auto p = head; p; p = p->next) res.push_back(p->val);
reverse(res.begin(),res.end());
return res;
}
};
class MyQueue{
public:
/** Initialize your data structure here.*/
stack<int> s1, s2;
MyQueue(){
}
/** Push element x to the back of queue. */
void push(int x) {
s1.push(x);
}
/*Removes the element from in front of queue and returns that element.*/
int pop(){
while (s1.size() > 1) s2.push(s1.top()),s1.pop();
int t = s1.top();
s1.pop();
while (s2.size()) s1.push(s2.top()),s2.pop();
return t;
}
/** Get the front element. */
int peek() {
while (s1.size()> 1) s2.push(sl.top()),s1.pop();
int t = s1.top();
while (s2.size()) s1.push(s2.top()),s2.pop();
return t;
}
/** Returns whether the queue is empty. */
bool empty() {
return s1.empty();
}
};
class Solution{
public:
vector<int> getLeastNumbers_Solution(vector<int> input, int k) {
sort(input.begin(),input.end());
vector<int> res;
for (int i = 0; i< k; i ++ ) res.push_back(input[i]);
return res;
}
};
哈希表的插入删除查找修改时间复杂度都是O(1)所以算法时间复杂度整个是O(n),看每个数的前面有没有数和相加有没有,没有就放到哈希表里,
class Solution{
public:
vector<int> findNumberswithSum(vector<int>& nums, int target) {
unordered set<int> S;
for (auto x : nums)
{
if (S.count(target - x)) return (x, target - x};
S.insert(x);
}
};
class Solution{
public:
vector<vector<int>> permutation(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<vector<int>> res;
do
{
res.push back(nums);
while (next_permutation(nums.begin(), nums.end()));//如果next_permutation(nums.begin(), nums.end())已经是最大的序列了,就会返回false,如果不是最大序列,就会返回true,next_permutation(nums.begin(), nums.end())可以帮助求一个排列大一点的下一个排列,每次调用就会返回一个大一点的下一个序列
}
return res;
}
};
//写法1
class Solution {
public:
int Numberof1(int n) {
int res = 0;
for (int i= 0;i<32;i++ )
if (n >> i & 1)
res ++ ;
return res;
}
};
//写法2lowbit
class Solution {
public:
int Numberof1(int n) {
int res = 0;
while (n) n -= n & -n, res ++ ;
return res;
}
};
#include
#include
using namespace std;
const int N = 11;
struct Data{
int x;
double y;
string z;
bool operator< (const Data &t) const{
return x < t.x;
}
}a[N];
int main()
{
int n;
cin >>n;
for (int i=0;i< n; i ++ ) cin >>a[i].x >> a[i].y >> a[i].z;
sort(a, a + n);
for (int i= 0;i<n; i ++ )
//cout << a[i].x <<' '<< a[i].y <<' '<< a[i].z << endl;
printf("%d %.2lf %s\n", a[i].x, a[i].y, a[i].z.c_str());
return 0;
}