最后
Python崛起并且风靡,因为优点多、应用领域广、被大牛们认可。学习 Python 门槛很低,但它的晋级路线很多,通过它你能进入机器学习、数据挖掘、大数据,CS等更加高级的领域。Python可以做网络应用,可以做科学计算,数据分析,可以做网络爬虫,可以做机器学习、自然语言处理、可以写游戏、可以做桌面应用…Python可以做的很多,你需要学好基础,再选择明确的方向。这里给大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!
👉Python所有方向的学习路线👈
Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。
👉Python必备开发工具👈
工欲善其事必先利其器。学习Python常用的开发软件都在这里了,给大家节省了很多时间。
👉Python全套学习视频👈
我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了。
👉实战案例👈
学python就与学数学一样,是不能只看书不做题的,直接看步骤和答案会让人误以为自己全都掌握了,但是碰到生题的时候还是会一筹莫展。
因此在学习python的过程中一定要记得多动手写代码,教程只需要看一两遍即可。
👉大厂面试真题👈
我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
C 阶乘约数
题目描述
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
定义阶乘 n! = 1 × 2 × 3 × · · · × n
请问 100!(100 的阶乘)有多少个正约数。
题解:
所谓的正约数,就是指约数是一个整数。
本题的暴力解:先求出100!,然后进行1~100!循环遍历,判断每个数是否是100!的约数即(100! % i==0) ,然而不幸的是100! 是非常大的,即使我们使用long long也存储不下,因此暴力解是无法实现的!
但是我们可以采用其他的方法,唯一分解定理进行求解;
什么是唯一分解定理,我们先不去理会。首先我们达成一个共识:一个数必定由n个质数相乘得到(质数仅有1和它本身相乘,而合数可以分解称若干个质数相乘,如4=2*2 ,因此任何数都可以分解成若干个质数相乘)
那这个与我们这道题有什么关系呢?
我们以5!为例 5!=5* 4 * 3 * 2 可以分解为5! =5 * ( 2 * 2)* 3 * 2
而唯一约数定理的内容
也就是说5!=2^3 * 3^1 * 5^1 ; 2,3,5就是p1,p2,p3即质数;其对应的指数a1,a2,a3就是3,1,1
再根据约束个数定理:我们将 指数+1 再全部相乘就可以得到我们想要的结果。
2^3 的约数为1 2 4 8
3^1 的约数为1 3
5^1 的约数为1 5
这些约数再次相乘又会得到其他的约数,这就是约数个数定理;
我们采用暴力方法来确认依靠两个定理解题是否正确,根据定理解的5!的约数个数为16 ,与暴力解的结果相同
暴力解验证:
int main(){
int result=0;
int num=1;
for(int i=1;i<=5;++i)
{
num\*=i;
}
for(int i=1;i<=num;i++){
if(num%i==0)
{
cout<<i<<endl;
result++;
}
}
cout<<"result:"<<result<<endl;
return 0;
}
代码:
#include <iostream>
using namespace std;
int main(){
long long result=1;
int arr[101]={0}; //用来存储质数的指数 ,100以内数的约数不会超过100,故去数组大小为101
for(int i=1;i<=100;i++){
int tmp=i;
for(int j=2;j\*j<=tmp;j++){
if(tmp%j==0){
//如果找到约数,一直相除,就可以得到此约数的指数,这个约数一定是质数
//因为质数2,3在前面即使此处j=4或6,一定取余不为0,在前面已经被分解了
while(tmp%j==0){
tmp/=j;
arr[j]++;
}
}
}
if(tmp>1)
{
//设置该if语句的原因 eg:2 2\*2>2 ;进不去上面的for循环,我们需要再次判断,以防遗漏
//cout<<"i"<<i<<"tmp"<<tmp<<endl;
arr[tmp]++;
}
}
for(int i=0;i<101;i++){
if(arr[i]!=0)
result\*=(arr[i]+1);
}
cout<<result<<endl;
return 0;
}
题目链接:
https://www.lanqiao.cn/problems/1020/learning/
D 本质上升序列
题目描述:
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
小蓝特别喜欢单调递增的事物。
在一个字符串中,如果取出若干个字符,将这些字符按照在字符串中的顺序排列后是单调递增的,则成为这个字符串中的一个单调递增子序列。
例如,在字符串 lanqiao 中,如果取出字符 n 和 q,则 nq 组成一个单调递增子序列。类似的单调递增子序列还有 lnq、i、ano 等等。 小蓝发现,有些子序列虽然位置不同,但是字符序列是一样的,例如取第二个字符和最后一个字符可以取到 ao,取最后两个字符也可以取到 ao。小蓝认为他们并没有本质不同。
对于一个字符串,小蓝想知道,本质不同的递增子序列有多少个? 例如,对于字符串 lanqiao,本质不同的递增子序列有 21 个。它们分别是 l、a、n、q、i、o、ln、an、lq、aq、nq、ai、lo、ao、no、io、lnq、anq、lno、ano、aio。
请问对于以下字符串(共 200 个小写英文字母,分四行显示):
tocyjkdzcieoiodfpbgcncsrjbhmugdnojjddhllnofawllbhf
iadgdcdjstemphmnjihecoapdjjrprrqnhgccevdarufmliqij
gihhfgdcmxvicfauachlifhafpdccfseflcdgjncadfclvfmad
vrnaaahahndsikzssoywakgnfjjaihtniptwoulxbaeqkqhfwl
本质不同的递增子序列有多少个?
题解:
动态规划
dp[i] 表示前i个字符构成上升序列的个数
如果我们遍历到第j个字符,我们由两种选择:
1不将其加入上升序列,那么dp[j] =dp[j-1]
2将其加入上升序列,要构成上升序列,我们要找str[j]之前的字符,显然使用一维数组是无法满足我们解题需要的,因此我们重新构建二维数组
dp[ i ][ 26 ] 表示前i个字符以a+[0,26)字符结尾的上升序列的个数
如果我们遍历到第j个字符c,我们由两种选择:
1不将其加入上升序列,那么dp[j][c] =dp[j-1][c]
2将其加入上升序列,要构成上升序列,我们要找c之前的字符
for(int k=0;k<c-'a';k++){
dp[j][c]+=dp[j-1][k];
}
因为要构成本质不同的序列,我们需要知道前面最近的一个相同字符的位置
因此构造一个last数组,保存其位置;
代码:
#include <iostream>
#include<vector>
using namespace std;
int main(){
//给字符串前面增加一个空格,使得dp数组的含义容易理解
string str=" tocyjkdzcieoiodfpbgcncsrjbhmugdnojjddhllnofawllbhfiadgdcdjstemphmnjihecoapdjjrprrqnhgccevdarufmliqijgihhfgdcmxvicfauachlifhafpdccfseflcdgjncadfclvfmadvrnaaahahndsikzssoywakgnfjjaihtniptwoulxbaeqkqhfwl";
//字符串的大小
int size=str.size();
//cout<<"size"<<size<<endl;
//前面一个最近相同字母的位置
vector<int> last(26,0);
//动态规划数组 ,表示前i个字符,以‘a’+j字符结尾构成上升序列的个数
vector<vector<int> > dp(size,vector<int>(26,0));
for(int i=1;i<size;i++){
//直接舍弃第i个字符加入上升序列
for(int j=0;j<26;j++){
dp[i][j]=dp[i-1][j];
}
//将第i个字符加入上升子序列
//单独的一个元素可以作为一个上升子序列
dp[i][str[i]-'a']++;
//倘若当前字符为c ,我们需要找前面以a或者b结尾的字符,
//以此构成递增序列
for(int j=0;j<str[i]-'a';j++){
dp[i][str[i]-'a']+=dp[i-1][j];
}
//因为题目要求构成本质不同的序列,我们需要找到上一次字符,
//减去上一次字符对应的次数
//(ablb) ab由两种情况前两个字符构成ab
//第二种跳过第二个第三个字符与第四个字符构成b
//由于要求本质不同的上升序列,我们需要减去重复的情况
dp[i][str[i]-'a']-= dp[last[str[i]-'a']][str[i]-'a'];
//更新字符的位置
last[str[i]-'a']=i;
}
long long result=0;
for(int i=0;i<26;i++){
result+=dp[size-1][i];
}
cout<<result<<endl;
return 0;
}
题目链接:
https://www.lanqiao.cn/problems/1021/learning/
E 玩具蛇
题目描述
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
小蓝有一条玩具蛇,一共有 16节,上面标着数字 1至 16。每一节都是一个正方形的形状。相邻的两节可以成直线或者成 90 度角。
小蓝还有一个 4 × 4的方格盒子,用于存放玩具蛇,盒子的方格上依次标着字母 A到 P 共 16 个字母。
小蓝可以折叠自己的玩具蛇放到盒子里面。他发现,有很多种方案可以将玩具蛇放进去。
下图给出了两种方案:
请帮小蓝计算一下,总共有多少种不同的方案。如果两个方案中,存在玩具蛇的某一节放在了盒子的不同格子里,则认为是不同的方案。
题解:
这道目的话,其实考察的是dfs算法,也可以认为是回溯算法:
也许你并不了解这算法,但是实现很简单:
- 我们需要设定一个起点
- 从起点选择一个方向(上下左右)进行移动
- 继续执行步骤2,直到我们把整个4*4方盒全部放满后,就是一种存放方案
代码:
#include <iostream>
#include<vector>
using namespace std;
//某个位置放有字符0,表示可以放置字符
vector<vector<char> > vv(4,vector<char>(4,'0'));
int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
void dfs(int row,int col,int count,int& result){
//我们将16个字符全部防止完毕之后,构成一种方法
if(count>=16){
result++;
return;
}
//选择四个方向中的一个方向移动
for(int i=0;i<4;i++){
int x=row+dir[i][0];
int y=col+dir[i][1];
//判断移动后的位置是否合理,越界不合理,我们不能移动;
//要移动的位置如果已经存放过东西,也不合理,不进行移动
if(x<0||x>=4||y<0||y>=4){
continue;
}
if(vv[x][y]!='0'){
continue;
}
//存放我们要防止的字符
vv[row][col]=count+'0';
dfs(x,y,count+1,result);
//上一次方法完毕,将该位置字符清除
vv[row][col]='0';
}
}
int main(){
int result=0;
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
//利用双重循环,使得方盒每个位置都可以设置为起点
dfs(i,j,1,result);
}
}
cout<<result<<endl;
return 0;
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化学习资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618317507)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**