目录
题目一:
给定一个字符串,计算字符串中数值的个数并求和。其中还包含了负号,若紧跟负号的是一个数值,则表示这是一个负数,若后面跟着的不是数字,则不表示什么。输入:一个字符串输出:数值个数数值和列子
输入:312ab-2—9–a
输出:3 301
多年不写代码,现在写个这么简单的判断都如此笨拙,而且代码丑陋无比,后来的考杭电的大佬,如果有更好的思路,麻烦在下面贴出你的代码,以便大家学习
思路:
1.对这个字符串进行暴力遍历。
2.如果遍历过程中遇到“-”号,并且”-“号后面就是数字的话,那么就进入一个死循环,并且更新暴力指针,直到把这个负数完整的取出来,解除死循环,继续暴力该字符串。
3.如果遇到数字的话,那么就可以肯定他一定是正数,负数的话一定会走第二步,走不到这一步的。进入死循环,更新暴力指针,把这个字符串存储到一个临时数组中,然后使用atoi函数,将这个字符串转换成数字即可。
4.我们把2,3两步中取出来的字符串放入到一个sum数组当中。
5.把sum数组中取出来的所有正数或者负数,进行累加求和。我们就可以得到最终的结果。
方法一:
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<iostream>
#include<string.h>
using namespace std;
int main(){
string str;
cin>>str;
int sum[100],sum_cnt=0;
char tmp[20];//中间变量,用来截取数字
for(int i=0;i<str.length();i++){//从头到尾开始进行遍历
//memset(tmp,0,sizeof(tmp));//初始化字符串
int tmp_cnt=0;
if(str[i]<='9'&&str[i]>='0'){
while(true){//处理正数
if(str[i]<='9'&&str[i]>='0'){
//如果是数字,开始把这个数存储到数组里,然后走到不是数字为止。进行字符转换
tmp[tmp_cnt++]=str[i];
i++;
}
else{
tmp[tmp_cnt]=0;//输入字符串结束符。
tmp_cnt=0;//重新初始化,准备下次使用
sum[sum_cnt++]=atoi(tmp);
break;
}
}
}
if(str[i]=='-'&&str[i+1]<='9'&&str[i+1]>='0'){
while(true){
i++;//开始从数字位置开始暴力。
if(str[i]<='9'&&str[i]>='0'){
//如果当前位置是负号,并且下一位是数字,将数字存储到一起
tmp[tmp_cnt++]=str[i];
}
else{
tmp[tmp_cnt]=0;//输入字符串结束符。
sum[sum_cnt++]=-atoi(tmp);//将取出的数值置为负数
break;
}
}
}
}
int ans=0;
for(int i=0;i<sum_cnt;i++)
ans+=sum[i];
cout<<sum_cnt<<" "<<ans<<endl;
return 0;
}
0325日重新修改以上代码,套用函数将其中的取数操作变得简单化一些
方法二:
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<fstream>
#define MAX 1010
using namespace std;
char a[1010];
char temp[1010];//该数组用来存储分隔开的整数。
int sum[1010],sum_cnt,i;
void qushu(){
int cnt=0;//记录数字长度
if(a[i]=='-'){//先对符号进行处理,后面就可以进行统一化。
temp[cnt++]='-';
i++;
}
for(;i<strlen(a);i++){//
if(a[i]>='0'&&a[i]<='9')
temp[cnt++]=a[i];
else
break;
}
temp[cnt]=0;//每取出一次数,就把数组最后一位置为字符串结束标志
sum[sum_cnt++]=atoi(temp);
i--; //跳出函数之后还是for循环,这可能就会导致直接跳两个字符,所以缩减一下
}
int main(){
cin>>a;
sum_cnt=0;//记录有多少个整数
for(i=0;i<strlen(a);i++){
if(a[i]=='-'&&a[i+1]>='0'&&a[i+1]<='9')//如果该数是负数
qushu();
else if(a[i]>='0'&&a[i]<='9')//如果该数是正数
qushu();
//这两个条件判断应该是非此即彼的关系。所以我们最好用else if进行连接
}
int ans=0;
for(int i=0;i<sum_cnt;i++)
ans+=sum[i];
cout<<sum_cnt<<" "<<ans<<endl;
return 0;
}
方法三:
来自半墨生烟的写法
利用i=i+j来更新指针,我觉得还蛮巧妙的。
#include<stdio.h>
#include<string.h>
int main()
{
int i,j,sum=0,temp=0,len,t=0,flag=1;
char a[1000];
gets(a);
len=strlen(a);
for(i=0;i<len;i++)
{
if(a[i]=='-'&&a[i+1]>='0'&&a[i+1]<='9')//如果为负数
{
temp=0;
for(j=1;a[i+j]>='0'&&a[i+j]<='9';j++)
temp=temp*10+a[i+j]-'0';//临时存一个数
i=i+j;
sum-=temp;
t++;
}
else if(a[i]>='0'&&a[i]<='9')//如果为正数
{
temp=0;
for(j=0;a[i+j]>='0'&&a[i+j]<='9';j++)
temp=temp*10+a[i+j]-'0';
i=i+j;
sum=sum+temp;
t++;
}
}
printf("%d %d\n",t,sum);
return 0;
}
给定一个数字矩阵,如果上下左右数值相同,则表示是一个连通的区域。求矩阵中连通块的数量。输入:先是矩阵的行数和列数接着是矩阵输出:连通块的数量
例子
5 6
4 4 4 4 4 4
4 2 3 3 1 4
4 2 2 3 1 4
4 2 3 3 1 4
4 4 4 4 4 4
输出
4
说明所有4能连起来,还有2 3 1,都有各自能连通块。
思路:
这道题有很明显的BFS倾向,然后我就用BFS做了。。。
1、设置一个判断模块儿,(BFS最恶心的一个地方就是,它乱走,很有可能就会越界,或者直接走你走过的地方。)所以你需要设置一个判断模块儿,看自己是否走出地图的范围了,或者看一下你是不是走的是之前已经走过的路。而且这道题有个特点就是,只有两个字符相同了,你才能到达,他们之间才有路。
2、宽搜模块儿,实现一个点到它上下左右四个位置的遍历,对每一个位置进行判断。若判断模块儿为真,就加入队列,若为假,就说明该位置不可用。
宽搜流程:
- 先把第一个点放入队列(这个点是我们宽搜的起点),并标记为访问过了。
- 进入一个循环,条件为队列不空。这个是告诉我们只要你还有走路的可能,你就要一直走下去。
- 每次循环取出队头,然后出队,标记为访问过。
- 对取出的队头进行上下左右四个位置的尝试,每次尝试都判断一下是否能够满足判断模块儿,满足就入队,不满足就continue
3、我们要判断的是连通性。那我们要知道一点,需要一次BFS就能访问到所有节点的图一定是一个连通。需要两次才能访问完的一定是两个连通。我们利用这个性质写一个判断。如果BFS后还有没被访问过的点,那么连通的数量就+1.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<queue>
#include<iostream>
#define MAX 150
using namespace std;
struct N{
int x,y;
}now,tmp;
queue<N>q;
int map[MAX][MAX],n,m;
int X[4] = {0,0,1,-1};
int Y[4] = {1,-1,0,0};
bool visit[MAX][MAX];
bool judge(int x,int y,int value){//判断下一层的点是否符合规范
if(x>n||y>m||x<0||y<0)//越界不合法
return false;
else if(visit[x][y])//访问过不合法
return false;
else if(map[x][y]==value)//存储的值相同代表术语同一个区域
return true;
else
return false;
}
void BFS(int x,int y,int value){
int newx, newy;
tmp.x=x;tmp.y=y;
q.push(tmp);
visit[tmp.x][tmp.y]=true;//标记为已经访问过
while(!q.empty()){
now =q.front();
q.pop();//从队头中取出元素。
for(int i=0;i<4;i++){
newx = now.x + X[i];
newy = now.y + Y[i];
if(judge(newx,newy,map[now.x][now.y])){
//进行比对,看是否是连通的。
//传给judge的是now节点的值,我们要得到的是now节点和temp节点比对之后的结果。
tmp.x=newx;tmp.y=newy;
q.push(tmp);
visit[tmp.x][tmp.y]=true;
}
}
}
}
int main(){
cin>>n>>m;
for(int i=0;i<n;i++)//开始创建图
for(int j=0;j<m;j++)
cin>>map[i][j];
int ans=0;
memset(visit,false,sizeof(visit));
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
if(!visit[i][j]){//如果该节点还没有被访问过,就说明是一个新的连通区
ans++;
BFS(i,j,map[i][j]);
}
}
cout<<ans<<endl;
}
写法二:
思路是一样的,不过中间有一点点的写法上的不同。Update 0325
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<fstream>
#include<queue>
#define MAX 1010
using namespace std;
int X[4]={0,0,1,-1},Y[4]={1,-1,0,0};
char map[MAX][MAX];
int n,m;
bool visit[MAX][MAX];
struct loc{
int x;
int y;
char value;
}now,temp;
bool judge(int x,int y,char value){//value标记现在表示通路的字符
if(x>=n||y>=m||x<0||y<0)//越界
return false;
if(visit[x][y])//如果已经访问过了
return false;
if(map[x][y]==value)//如果该位置的值也是通路上的值
return true;
return false;
}
void BFS(int x,int y,char value){
now.x=x;now.y=y;
now.value=value;
queue<loc>q;
q.push(now);
visit[x][y]=true;
while(!q.empty()){
now=q.front();
q.pop();
for(int i=0;i<4;i++){
temp.x=now.x+X[i];
temp.y=now.y+Y[i];
temp.value=map[temp.x][temp.y];
if(judge(temp.x,temp.y,now.value)){
q.push(temp);
visit[temp.x][temp.y]=true;
}
}
}
}
int main(){
int ans=0;
cin>>n>>m;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
cin>>map[i][j];
memset(visit,false,sizeof(visit));
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(!visit[i][j]){//如果还没被访问过,就说明肯定还有连通块儿
ans++;
BFS(i,j,map[i][j]);
}
cout<<ans<<endl;
return 0;
}
做法三:DFS
感觉最近几年的试题明显有很强的深搜倾向,大部分题都是和深搜相关的
代码如下:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#define N 101
using namespace std;
bool visit[N][N];//标记是否访问过该节点
int DFS_COUNT;//记录有多少个连通分量
int X[4]={0,0,1,-1},Y[4]={1,-1,0,00};//坐标转移数组
int n,m;//输入图的大小
char map[N][N];//用来存储图
bool judge(int x,int y,char value){
if(x>=n||x<0||y>=m||y<0)//如果越界就返回false
return false;
if(visit[x][y])//如果访问过
return false;
if(map[x][y]==value)//如果字符相同才表示这一条是通路
return true;
return false;
}
void dfs(int x,int y){
visit[x][y]=true;
for(int i=0;i<4;i++ ){//进行图的上下左右的遍历
int newx=x+X[i];
int newy=y+Y[i];
if(judge(newx,newy,map[x][y]))//如果该位置满足条件就递归
dfs(newx,newy);
}
}
void DFS(){
memset(visit,false,sizeof(visit));//初始化访问数组
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)//对整个图进行遍历
if(!visit[i][j]){
DFS_COUNT++;
dfs(i,j);
}
}
int main(){
cin>>n>>m;
for(int i=0;i<n;i++)//存储图
for(int j=0;j<m;j++)
cin>>map[i][j];
DFS();//进行深搜
cout<<DFS_COUNT<<endl;//输出连通个数
return 0;
}
这道题如果稍微扩展下的话,可以和今年的初试题目一样,让你去判断环,判环的话,其实还是蛮难的,至今没有什么好的思路,对于上面这道题,我们能看到一个回路,就那个全是“4”的圈儿,哪个大佬说一下怎么判断出有这个环