【腾讯云智】20250329笔试算法题
文章目录
- 第一题
- 1. 题目描述
- 2. 思路解析
- 3. AC代码
- 第二题
- 1. 题目描述
- 2. 思路解析
- 3. AC代码
- 第三题
- 1. 题目描述
- 2. 思路解析
- 3. AC代码
第一题
1. 题目描述
题目链接:牛牛的水果店
2. 思路解析
这题比较简单,按数学思维把题目的意思翻译过来就是给你一个区间[l,r]
,另外给定一个整数n
。然后让你找个最小的整数a、最大的整数b其中a<=b,满足如下条件:
- l<=a*n<=b
- l<=b*n<=b
- a<=b即a*n<=b*n
一句话描述就是l<=a*n<=b*n<=r
以输入2、6、9为例:
我们可以找打一个最小的数a=3满足6<=2*3<=9,如果a变成2就不满足了,所以最小就是3,然后可以找到一个最大的数b=4满足6<=2*4<=9,如果b=5的话就不满足了,所以b最大只能是4,所以最后输出3 4
以输入3、7、8为例
找不到一个最小值a满足7<=3*a<=8,也找不到一个最大值b所以输出-1
以输入1、6、6为例
容易得出最大值最小值都是6,所以输出6 6
写代码的时候我们只需要判断一下l能不能整除n,能整除的话,那最小值a就是a=l/n
,不能整除的话,那最小值就是a=l/n+1
,之后要判断一下这个a满不满足a*n<=r
,满足的话才是最小值,不满足的话,那就直接输出-1了,并且跳出本次循环。
求b的话直接b=r/n
即可,无需过多判断,因为能走到这一步说明一定有最小值,那么就一定存在最大值,这个最大值再小也就是和最小值相等嘛,所以不需要过多判断。
最后直接输出a b即可。
3. AC代码
#include <iostream>
using namespace std;
int main(){
int k=0;
cin>>k;
while(k--){
int n=0,l=0,r=0;
cin>>n>>l>>r;
int min=-1,max=-1;
if(l%n==0) min=l/n;
else{
min=l/n+1;
if(min*n>r){
cout<<-1<<endl;
continue;
}
}
max=r/n;
cout<<min<<" "<<max<<endl;
}
return 0;
}
第二题
1. 题目描述
题目链接:acmer数组
2. 思路解析
这个题我觉得本身不难,但对于我来说读题读了老半天,因为我实在是读不懂题目中的:将一个字母改为另一个大小写相同的字母,花费为 5
这句话是啥意思,什么叫大小写相同的字母?26个英文字母哪个字母的大小写一样啊?
后来才反应过来,原来它的意思是你可以把一个字母改成另一个字母,但是原来是大写
字母,你只能改为其它的大写
字母,不能改为小写字母,同理小写
字母也是,只能花5块钱改为另一个小写
字母,不能改成大写字母。
- 将一个字母改为另一个大小写相同的字母,花费为 5。
- 将一个字母由大写改为小写或者由小写改为大写花费为 5。
总结这两条规则就是你先看这俩字符大小写一不一样,如果大小写不一样,那就肯定得花5块钱转变一下大小写,然后再看一下这俩字符一不一样,如果不一样那就花5块钱把这个字符变成目标字符。
以Acaer为例:
- Acaer
- AcMer
对比一下要把1变成2不就是把中间的a改成M就好了嘛,首先这俩大小写不一样我可以先花5块用规则2变成AcAer,然后再花5块用规则1变成AcMer。一共花十块钱。
或者先花5块用规则1变成Acmer,然后再花5块用规则2变成AcMer,也是10块。
代码也很好写,维护一个大小为5的滑动窗口即可,每次判断相邻5个字符转换为目标字符AcMer
需要花多少钱,遍历所有结果,取最小值即可。
其中一次遍历可以先利用isupper判断这俩字符是不是都是大写或者都是小写,如果这俩大小写不一样的话就得+5,再判断这俩字符一不一样,不一样的话又得+5,5个字符全判断完后,取个最小值即可,对应代码中的ret=std::min(tmp,ret);
3. AC代码
#include <iostream>
#include <string>
#include <climits>
using namespace std;
int main(){
string str;
cin>>str;
string ac("AcMer");
int ret=INT_MAX;
for(int i=0;i<=str.size()-5;i++){
int tmp=0;
for(int j=i;j<i+5;j++){
char a=str[j],b=ac[j-i];
if(isupper(a)!=isupper(b)) tmp+=5;
if(tolower(a)!=tolower(b)) tmp+=5;
}
ret=std::min(tmp,ret);
}
cout<<ret;
}
第三题
1. 题目描述
题目链接:生化危机
2. 思路解析
虽然是第三道题,但难度也不是很大,如果dfs写的多的话,这题算是打卡题了,不难。
类似力扣hot100中的岛屿数量这种题,多刷几道,写这个笔试题就得心应手了。
先弄个vis二维数组记录哪些位置已经被遍历过了,保证被遍历过的位置不再重新调用dfs进行遍历即可。main函数中二维数组直接遍历,如果该位置不为0即有僵尸,且vis[i][j]=false代表没被遍历过,那就直接把vis[i][j]=true,然后tmp=arr[i][j]表示这一个范围tmp即僵尸的初始数量然后++cnt,表示块数+1,然后调用dfs即可。
dfs中对上下左右四个方向进行遍历,如果x、y没有越界且该位置有僵尸即arr[x][y]!=0
且没被遍历过即vis[x][y]==false
,就把该位置设置为true,并tmp+=arr[x][y],然后继续dfs即可
最后main函数中把每个块的僵尸数量取个最大值即可,即ret=max(ret,tmp);
最后输出结果即可。
注意的是:要测试多组数据,所以我这里用的是全局变量,每组数据都必须对全局变量进行归零操作即ret=0; vis=vector<vector<bool>>(m,vector<bool>(n,false));
以后可以尝试一波利用function接受lambda用&全部捕获,这样就不需要用全局变量了。
3. AC代码
#include <iostream>
#include <vector>
using namespace std;
int dx[4]={0,0,-1,1};
int dy[4]={-1,1,0,0};
vector<vector<bool>> vis;
int m,n,ret=0,tmp=0;
void dfs(vector<vector<int>> &arr,int i,int j){
for(int k=0;k<4;k++){
int x=i+dx[k],y=j+dy[k];
if(x>=0&&x<m&&y>=0&&y<n&&arr[x][y]!=0&&vis[x][y]==false){
vis[x][y]=true;
tmp+=arr[x][y];
dfs(arr,x,y);
}
}
}
int main(){
int k=0;
cin>>k;
while(k--){
cin>>m>>n;
vector<vector<int>> arr(m,vector<int>(n,0));
for(int i=0;i<m;i++){
for(int j=0;j<n;j++)
cin>>arr[i][j];
}
int cnt=0;
ret=0;
vis=vector<vector<bool>>(m,vector<bool>(n,false));
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(arr[i][j]!=0&&vis[i][j]==false){
vis[i][j]=true;
tmp=arr[i][j];
dfs(arr,i,j);
++cnt;
ret=max(ret,tmp);
}
}
}
cout<<cnt<<" "<<ret<<endl;
}
return 0;
}