腾讯软件后台开发0426笔试-超详细题目+C++实现
总体感受
成绩还算满意,100+60+0+100+100,两道数据结构的题都比较基础,欢迎指正和参考🤣
题目1:模拟队列
我老老实实用的链表实现,花了我三十分钟,我当场裂开……
输入样例:
第一行输入样例数T,之后每个样例,先输入操作数Q,然后进行"PUSH", "TOP", "POP", "SIZE","CLEAR"五种操作。
输出样例:
"TOP"输出队头元素,队伍空返回-1;"POP"失效时输出-1。
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
struct node{
int val;
node* next;
node(int x):val(x),next(nullptr) {}
};
class myQueue{
public:
myQueue(){
dummyNode=new node(0);
length=0;
}
~myQueue(){
delete dummyNode;
dummyNode=nullptr;
length=0;
}
void push(int x){
node* lastNode=dummyNode;
while(lastNode->next){
lastNode=lastNode->next;
}
node* newNode=new node(x);
lastNode->next=newNode;
length++;
}
void top(){
if(length==0){
printf("%d\n",-1);
}
else{
printf("%d\n",dummyNode->next->val);
}
}
void pop(){
if(length==0){
printf("%d\n",-1);
}
else{
node* head=dummyNode->next;
dummyNode->next=head->next;
delete head;
length--;
}
}
void size(){
printf("%d\n",length);
}
void clear(){
delete dummyNode->next;
dummyNode->next=nullptr;
length=0;
}
private:
node* dummyNode;
int length;
};
int main(){
int T;
scanf("%d",&T);
for(int i=0;i<T;i++){
myQueue q;
int Q;
scanf("%d", &Q);
for(int j=0;j<Q;j++){
string s;
//s.resize(4);
//scanf("%s",&s[0]);
cin>>s;
//cout<<s<<endl;
if(s=="PUSH"){
int i;
scanf("%d",&i);
q.push(i);
}
else if(s=="TOP"){
q.top();
}
else if(s=="POP"){
q.pop();
}
else if(s=="SIZE"){
q.size();
}
else if(s=="CLEAR"){
q.clear();
}
}
}
return 0;
} 题目2:求两个点集合的最短距离
给定两个相同规模的点集合(大小为n),计算集合间的最低距离。这里的距离是欧式距离,然后暴力枚举的,通过60%。希望AC的朋友指点下本弱鸡,之后会更新AC答案的,感谢~ 输入样例:
第一行输入集合规模n,然后输入集合A和B的点坐标,每行是点的横坐标和纵坐标,先输入A再输入B
例如:
4
0 1
1 1
1 0
1 1
2 2
2 3
3 2
3 3
输出样例:两个集合间的最短距离
例如:上样例中,集合A的[1,1]和集合B的[2,2]距离最短,距离是1.414(保留三位小数)
#include <stdio.h>
#include <vector>
#include <cmath>
using namespace std;
vector<int> ax;
vector<int> ay;
vector<int> bx;
vector<int> by;
inline double calDist(int a, int b){
return sqrt(pow(ax[a]-bx[b],2)+pow(ay[a]-by[b],2));
}
int main(){
int N;
scanf("%d",&N);
for(int i=0;i<N;i++){
int n;
scanf("%d", &n);
ax.assign(n,-1);
ay.assign(n,-1);
bx.assign(n,-1);
by.assign(n,-1);
for(int j=0;j<n;j++){
scanf("%d %d", &ax[j], &ay[j]);
}
for(int j=0;j<n;j++){
scanf("%d %d", &bx[j], &by[j]);
}
double dist=calDist(0,0);
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
double tmp=calDist(i,j);
if(tmp<dist) dist=tmp;
}
}
printf("%.3f\n", dist);
}
} 4月28日更新:
在ACWING上找到原题,并参考了一位大佬的思路(分治+二分),他的讲解十分清晰,链接是:https://www.acwing.com/solution/acwing/content/826/
自己重写了一遍代码,如下:
#include <bits/stdc++.h>
using namespace std;
const int N=1000005;
#define INF 1e8
struct point{
double x,y;
int f; // 集合
} P[N], T[N];
bool comp1(point a, point b){ // 根据x优先排序
if(a.x==b.x) return a.y<b.y;
return a.x<b.x;
}
bool comp2(point a, point b){ // 根据y优先排序
if(a.y==b.y) return a.x<b.x;
return a.y<b.y;
}
double dist(point a,point b){
if(a.f==b.f) return INF; // 同种类,距离设为INF
double x2=(a.x-b.x)*(a.x-b.x);
double y2=(a.y-b.y)*(a.y-b.y);
return sqrt(x2+y2);
}
double minDist(int l,int r){
if(l==r) return INF;
if(l+1==r) return dist(P[l],P[r]);
int m=(l+r)>>1;
double ans=min(minDist(l,m),minDist(m+1,r)); // 分治左右平面的最短距离
// 寻找中间距离
int cnt=0;
for(int i=l;i<=r;i++){
if(abs(P[m].x-P[i].x)<=ans) T[++cnt]=P[i]; // 排除离平面分界线过远的点
}
sort(T+1,T+1+cnt,comp2);
for(int i=1;i<=cnt;i++){
for(int j=i+1;j<=cnt;j++){
if(T[j].y-T[i].y>=ans) break; // 根据y坐标剪枝
ans=min(ans,dist(T[i],T[j]));
}
}
return ans;
}
int main(){
int t;
cin>>t;
while(t--){
int n;
cin>>n;
int i;
for(i=1;i<=n;i++){
cin>>P[i].x>>P[i].y;
P[i].f=0;
}
for(i=n+1;i<=n<<1;i++){
cin>>P[i].x>>P[i].y;
P[i].f=1;
}
sort(P+1,P+1+(n<<1),comp1);
printf("%0.3lf\n", minDist(1,n<<1));
}
} 题目3:翻转卡片
n张卡片排成一行,每张卡片的正面和背面均有数字,一开始所有卡片正面朝上。有一种操作是将相邻卡片交换位置,并且两张卡片翻面。求这种操作的最少次数,使得卡片所显示的、排成一行的数字能够实现非严格递增排序。如果不存在这个最少次数,则返回-1。我总感觉像是冒泡排序,但死活没想出来,希望AC的朋友指点下本弱鸡,之后会更新AC答案的,感谢~ 输入样例:
第一行是卡片数(n<=18)
第二行是卡片正面数字的数组
第三行是卡片背面数字的数组
例如:
3
1 3 2
3 2 1
输出样例:
1 (操作的最少次数,不能实现则为-1)
题目4:两个栈模拟队列
《剑指offer》里的第九题:https://leetcode-cn.com/problems/yong-liang-ge-zhan-shi-xian-dui-lie-lcof/,大体思路是两个栈分别扮演队列的队头和队尾,入队操作在队尾栈里,出队和检查队头在队头栈中,中途要维护队尾栈向队头栈的元素转移。
输入样例:
第一行是操作数N
之后有N行操作,有“add”,“peek”和“poll”三种操作
输出样例:
“peek”操作需输出队头元素
#include <stdio.h>
#include <iostream>
#include <stack>
using namespace std;
//int add_pos=0;
void add(stack<int>& stack1, stack<int>& stack2, int i){
stack1.push(i);
}
void peek(stack<int>& stack1, stack<int>& stack2){
if(stack2.empty()){
if(stack1.empty()) return;
while(!stack1.empty()){
int tmp=stack1.top();
stack1.pop();
stack2.push(tmp);
}
}
printf("%d\n", stack2.top());
}
void poll(stack<int>& stack1, stack<int>& stack2){
if(stack2.empty()){
if(stack1.empty()) return;
while(!stack1.empty()){
int tmp=stack1.top();
stack1.pop();
stack2.push(tmp);
}
}
stack2.pop();
}
int main(){
stack<int> stack1,stack2;
int N;
scanf("%d", &N);
for(int i=0;i<N;i++){
string s;
cin>>s;
if(s=="add"){
int i;
scanf("%d", &i);
add(stack1,stack2,i);
}
else if(s=="peek"){
peek(stack1,stack2);
}
else if(s=="poll"){
poll(stack1,stack2);
}
}
return 0;
} 题目5:满二叉树的祖先节点
有一个无穷高的满二叉树,层次遍历从小到大编号,根结点从1开始,第二行是“2 3”,第三行是“4 5 6 7”……对于编号为n的结点,求其高度为k的祖先节点,若不存在则返回-1. 思路:满二叉树的层级编号是一个很经典的问题,编号为n的节点的父结点编号是n>>1,祖父节点编号是n>>2……以此类推。另外,树高为k的节点编号范围是[2^(k-1), 2^k),所以编号为n的节点的树高为⌊log2(n)⌋+1,进而当k>=⌊log2(n)⌋+1时,不存在该祖先节点。
输入样例:
第一行是检索数Q
下面Q行的检索中,每一行包含节点编号i和祖先节点高度k
例如:
4
10 1
10 2
10 3
10 4
输出样例:
每行检索对应的祖先节点编号
例如:
1
2
5
-1
#include <stdio.h>
using namespace std;
int calHeight(long long x){
int height=1;
long long tmp=1;
while(1){
if(x>=tmp && x<(tmp<<1)) break;
height++;
tmp=tmp<<1;
}
return height;
}
int main(){
int Q;
scanf("%d",&Q);
for(int i=0;i<Q;i++){
long long x;
int k;
scanf("%lld %d", &x, &k);
int height=calHeight(x);
if(k>=height) printf("%d\n", -1);
else{
long long ret=x>>(height-k);
printf("%lld\n", ret);
}
}
} 另外,弱鸡的我求教下各位C++的格式输入/输出到底怎样规范操作?我经常将scanf和cin混用,也经常碰到一些输入/输出样例处理的bug,各位收藏过整理这些输入/输出的网站吗?谢谢

