腾讯2017秋招编程题

来源:互联网 发布:即时通讯软件怎么开发 编辑:程序博客网 时间:2024/06/05 10:46

[编程题] 素数对

时间限制:1秒
空间限制:32768K

给定一个正整数,编写程序计算有多少对质数的和等于输入的这个正整数,并输出结果。输入值小于1000。如,输入为10, 程序应该输出结果为2。(共有两对质数的和为10,分别为(5,5),(3,7))
输入描述:
    输入包括一个整数n,(3 ≤ n < 1000)
输出描述:
    输出对数
输入例子1:
10
输出例子1:
2

解析:

求素数问题,一般用筛法,有线性筛法、快速线性筛法,欧拉筛法等。

线性筛法:

偶数(除2外)肯定不是素数,刚开始默认奇数都是素数。
当找到一个素数,显然这个素数乘以另一个数后都是合数,因此可以筛掉。筛的时候从i*i开始,步长为2i,这样比从2i开始筛要快。
分析发现,当数字非常大时,这种方法会重复筛出合数,影响效率。

快速线性筛法、欧拉筛法

快速线性法不会重复筛出一个数。

C++代码实现:
线性筛法版:

#include <iostream>#include <math.h>using namespace std;bool primeDict[1001]={false};void prime(){    primeDict[2] = true;    int upper = sqrt(1000);    for(int i=3; i<=1000; i+=2)        primeDict[i] = true;    //假设所有奇数是质数    for(int i=3; i<upper; i+=2) {        if(primeDict[i]==true){            for(int j=i*i; j<=1000; j+=2*i){ //从i*i开始排除,比i*2开始要快                primeDict[j] = false;            }        }    }}int main(){    int n,count=0;    cin>>n;    if(n<3 || n>1000)        return 0;    int upbound = n>>1;    prime();    for(int i=2; i <= upbound; i++) {      if(primeDict[i] && primeDict[n-i])            count++;    }    cout<<count;    return 0;}

欧拉筛法

#include <iostream>#include <math.h>using namespace std;bool primeDict[1001]={false};int primes[1001] = {0};int pcount = 0;void prime(){    primes[pcount++]=2;    primeDict[2]=true;    for(int i=3; i<=1000; i+=2)        primeDict[i]=true;    for(int i=3; i<1000; i+=2) {        if(primeDict[i]==true){            primes[pcount++] = i;        }        for(int j=0; j<pcount && i*primes[j]<=1000; j++) {            primeDict[i*primes[j]] = false;            if(i%primes[j]==0) //关键                break;        }    }}int main(){    int n,count=0;    cin>>n;    if(n<3 || n>1000)        return 0;    int upbound = n>>1;    prime();    for(int i=2; i <= upbound; i++) {      if(primeDict[i] && primeDict[n-i])            count++;    }    cout<<count;    return 0;}

[编程题] geohash编码

时间限制:1秒
空间限制:32768K
geohash编码:geohash常用于将二维的经纬度转换为字符串,分为两步:第一步是经纬度的二进制编码,第二步是base32转码。
此题考察纬度的二进制编码:算法对纬度[-90, 90]通过二分法进行无限逼近(取决于所需精度,本题精度为6)。注意,本题进行二分法逼近过程中只采用向下取整来进行二分,针对二分中间值属于右区间。算法举例如下: 针对纬度为80进行二进制编码过程:
1) 区间[-90, 90]进行二分为[-90, 0),[0, 90],成为左右区间,可以确定80为右区间,标记为1;
2) 针对上一步的右区间[0, 90]进行二分为[0, 45),[45, 90],可以确定80是右区间,标记为1;
3) 针对[45, 90]进行二分为[45, 67),[67,90],可以确定80为右区间,标记为1;
4) 针对[67,90]进行二分为[67, 78),[78,90],可以确定80为右区间,标记为1;
5) 针对[78, 90]进行二分为[78, 84),[84, 90],可以确定80为左区间,标记为0;
6) 针对[78, 84)进行二分为[78, 81), [81, 84),可以确定80为左区间,标记为0;
输入描述:
    输入包括一个整数n,(-90 ≤ n ≤ 90)
输出描述:
    输出二进制编码
输入例子1:
80
输出例子1:
111100

C++代码实现:

#include <iostream>using namespace std;int main(){    int n,count=6;    cin>>n;    if(n<-90 || n>90)        return 0;    int left=-90,right=90,mid=0;    while(count>0) {        mid = (left+right)/2;        if(n<mid){            right = mid;            cout<<0;        }        else{            cout<<1;            if(n>mid)                left = mid;            else{                while(--count>0)                    cout<<0;                break;            }        }        count--;    }    return 0;}

[编程题] 编码

时间限制:1秒
空间限制:32768K
假定一种编码的编码范围是a ~ y的25个字母,从1位到4位的编码,如果我们把该编码按字典序排序,形成一个数组如下: a, aa, aaa, aaaa, aaab, aaac, … …, b, ba, baa, baaa, baab, baac … …, yyyw, yyyx, yyyy 其中a的Index为0,aa的Index为1,aaa的Index为2,以此类推。 编写一个函数,输入是任意一个编码,输出这个编码对应的Index.
输入描述:
    输入一个待编码的字符串,字符串长度小于等于100.
输出描述:
    输出这个编码的index
输入例子1:
baca
输出例子1:
16331

解析:

以a开头的编码有:
1(a) + 25(a_) + 25*25(a_ )+25*25*25(a _ _) = 16276
即,a开头编码范围为[0,16275]
因此,所有的编码数为:25*16276 = 406900
其他字母开头编码范围可以依次类推,比如y开头编码范围为[390624, 406899]
可以看出:
(1)已知a的索引,求b的索引:因为a到b之间隔了以下四种情况的字符串:a后跟2字符的串有25个(aa,ab,…ay),a后跟2字符的串有25*25个(aaa, aab, … ayy),a后面跟3字符的串有25*25*25个(aaaa,aaab,…ayyy),然后才是b,所以b的索引 = a的索引 + 25+25*25+25*25*25 + 1,加1是因为b排在a和中间的字符之后1个
(2)已知aa的索引,求ab的索引:同理,ab的索引 = aa索引 + 25 + 25* 25 + 1
(3)已知aaa的索引,求aab的索引:同理,aab的索引 = aaa索引 + 25 + 1
(4)已知aaaa的索引,求aaab的索引 = aaaa索引 + 1
因此,得出以下推导公式,字符串为str
index = (str[0]-a)*16267 + (str[1]-a)*651 + (str[3]-a)*26 + (str[4]-a)*1 + (str.length-1)。

C++代码实现:


[编程题] 游戏任务标记

时间限制:1秒
空间限制:32768K
游戏里面有很多各式各样的任务,其中有一种任务玩家只能做一次,这类任务一共有1024个,任务ID范围[1,1024]。请用32个unsigned int类型来记录着1024个任务是否已经完成。初始状态都是未完成。 输入两个参数,都是任务ID,需要设置第一个ID的任务为已经完成;并检查第二个ID的任务是否已经完成。 输出一个参数,如果第二个ID的任务已经完成输出1,如果未完成输出0。如果第一或第二个ID不在[1,1024]范围,则输出-1。
输入描述:
    输入包括一行,两个整数表示人物ID.
输出描述:
    输出是否完成
输入例子1:
1024 1024
输出例子1:
1

解析:

32个int可以看成是一个32*32的位图, 总共1024位,每一位代表一个数
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
计算某个数在第几行第几列:
row = (num-1)/32, col = (num-1)%32
设置第k位为1:a | (1 << k)
取第k为: a>>k & 1

C++代码实现

#include <iostream>#include <stdio.h>using namespace std;int findTask(unsigned int task[32],int num){    int row = (num-1)/32;    int col = (num-1)%32;    return (task[row]>>(31-col)&1);}void setTask(unsigned int task[32],int num){    int row = (num-1)/32;    int col = (num-1)%32;    task[row] = task[row]|(1<<(31-col));  //设定某位为1}int main(){    unsigned int task[32] = {0};    int a,b;    while(scanf("%d %d",&a,&b)) {        if(a<1 || a>1024 || b<1 || b>1024)            cout<<-1<<endl;        else if(a==b){            setTask(task,a);            cout<<1<<endl;        }        else{            setTask(task,a);            cout<<findTask(task,b)<<endl;        }    }    return 0;}
原创粉丝点击