您的位置:首页 > 编程语言 > Python开发

2017年校招全国统一模拟笔试(第一场)编程题集合--Python

2017-06-30 16:50 453 查看
注:试题来源于牛客网

1.

牛牛有一个鱼缸。鱼缸里面已经有n条鱼,每条鱼的大小为fishSize[i] (1 ≤ i ≤ n,均为正整数),牛牛现在想把新捕捉的鱼放入鱼缸。鱼缸内存在着大鱼吃小鱼的定律。经过观察,牛牛发现一条鱼A的大小为另外一条鱼B大小的2倍到10倍(包括2倍大小和10倍大小),鱼A会吃掉鱼B。考虑到这个,牛牛要放入的鱼就需要保证:
1、放进去的鱼是安全的,不会被其他鱼吃掉
2、这条鱼放进去也不能吃掉其他鱼
鱼缸里面已经存在的鱼已经相处了很久,不考虑他们互相捕食。现在知道新放入鱼的大小范围[minSize,maxSize](考虑鱼的大小都是整数表示),牛牛想知道有多少种大小的鱼可以放入这个鱼缸。 

输入描述:

输入数据包括3行.
第一行为新放入鱼的尺寸范围minSize,maxSize(1 ≤ minSize,maxSize ≤ 1000),以空格分隔。

第二行为鱼缸里面已经有鱼的数量n(1 ≤ n ≤ 50)

第三行为已经有的鱼的大小fishSize[i](1 ≤ fishSize[i] ≤ 1000),以空格分隔。



输出描述:

输出有多少种大小的鱼可以放入这个鱼缸。考虑鱼的大小都是整数表示



输入例子:

1 12
1
1



输出例子:

3

个人思路:

我是从输入的鱼范围大小入手,从最小到最大,以此进行判断。
与鱼缸中鱼的大小做 /,如果能除尽,就是被吃。反之,则可以增加一次大小。
我的测试用例是 30% case
1 36
1
3
答案输出 10
我的是 8
鱼缸中的一条鱼大小是 3,则可放入鱼的大小为 2,3,4,5,7,8,10,11,13,14,16,17,19,20,22,23,25,26,28,29,31....
我是真没弄明白这题的意思。来看看正确答案吧。
分割线:
在分析了一波正确答案之后,我再看题,我明白了,2倍到10倍是一个什么概念!是区间啊大哥。我理解的是,是一个数的2倍,3倍,或者...10倍中的一个。

正确答案(牛客网 id:cheeeenkun):

minSize, maxSize = map(int,raw_input().split())
n = map(int,raw_input())
fishSize = map(int,raw_input().split())
put_in = range(minSize,maxSize+1)
cannot_input = 0
for x in put_in:
flag = 0
for i in fishSize:
if 2*x <= i <=x*10 or i*2 <= x <=i*10:
flag = 1
if flag == 1:
cannot_input += 1
print maxSize+1-minSize-cannot_input


2.

如果一个单词通过循环右移获得的单词,我们称这些单词都为一种循环单词。 例如:picture 和 turepic 就是属于同一种循环单词。 现在给出n个单词,需要统计这个n个单词中有多少种循环单词。 

输入描述:

输入包括n+1行:

第一行为单词个数n(1 ≤ n ≤ 50)

接下来的n行,每行一个单词word[i],长度length(1 ≤ length ≤ 50)。由小写字母构成



输出描述:

输出循环单词的种数



输入例子:

5
picture
turepic
icturep
word
ordw



输出例子:

2

个人思路:

必须是右移
不,这个是相对的
例子中,ture是右移的,但是pic就是相对左移
那简单了,先对每一个单词排序,然后set,最后len(set)

当时我是这样思考的,但测试用例 70% case,错误例子:

测试用例:
7
ast
ats
tas
tsa
sat
sta
ttt

对应输出应该为:

3

你的输出为:

2

果然我考虑的循环移动是有问题的,没有彻底思考究竟是什么循环右移。看到一个思路方法:
把要测试的单词后再重复下这个单词,如:picture ,变成 picturepicture

然后判断其他要测试的单词是不是这个串的子串(长度要先相等)

正确方法(牛客网 id:周昆):

def judge(word1, word2):
if len(word1) != len(word2):
return False
for i in range(len(word1)):
if word1[i:] + word1[:i] == word2:
return True
else:
return False

n = int(raw_input())
rec = list()
for i in range(n):
flag = True
word1 = raw_input()
for word2 in rec:
if judge(word1, word2):
flag = False
break
if flag:
rec.append(word1)
print len(rec)
这个貌似就是用了上面思路,通过 python 数组的分割 [3:] [:3] 来进行判断。就是以此把前面1,2..位的字符放到末尾去

so,循环右移就是把左边的连续字符移到右边去即可。

3.

DNA分子是以4种脱氧核苷酸为单位连接而成的长链,这4种脱氧核苷酸分别含有A,T,C,G四种碱基。碱基互补配对原则:A和T是配对的,C和G是配对的。如果两条碱基链长度是相同的并且每个位置的碱基是配对的,那么他们就可以配对合成为DNA的双螺旋结构。现在给出两条碱基链,允许在其中一条上做替换操作:把序列上的某个位置的碱基更换为另外一种碱基。问最少需要多少次让两条碱基链配对成功 

输入描述:

输入包括一行:
包括两个字符串,分别表示两条链,两个字符串长度相同且长度均小于等于50。



输出描述:

输出一个整数,即最少需要多少次让两条碱基链配对成功



输入例子:

ACGT TGCA



输出例子:

0

个人思路:

这题是属简单题,我这里用了先得出一条链的配对链,然后去计算另外一条链需要变化多少次

正确答案(本人&&牛客网 id:Panzerfaust):

def combine(arr):
wife = []
for a in arr:
if a == 'A':
wife.append('T')
elif a == 'T':
wife.append('A')
elif a == 'C':
wife.append('G')
elif a == 'G':
wife.append('C')
return wife

arr = [s for s in raw_input().strip().split()]
a = list(arr[0])
b = list(arr[1])
c = combine(a)
i = 0
count = 0
while i < len(a):
if c[i] != b[i]:
count += 1
i += 1
print count
精简的代码;
try:
while 1:
line = raw_input().split()
count =0
tmp = ["AT","TA","GC","CG"]
for i in range(len(line[0])):
if line[0][i]+line[1][i] not in tmp:
count+=1
print(count)
except:
pass
这个妙啊,妙啊,妙啊!!!

4.

牛牛的好朋友羊羊在纸上写了n+1个整数,羊羊接着抹除掉了一个整数,给牛牛猜他抹除掉的数字是什么。牛牛知道羊羊写的整数神排序之后是一串连续的正整数,牛牛现在要猜出所有可能是抹除掉的整数。例如:
10 7 12 8 11 那么抹除掉的整数只可能是9
5 6 7 8 那么抹除掉的整数可能是4也可能是9


输入描述:

输入包括2行:

第一行为整数n(1 <= n <= 50),即抹除一个数之后剩下的数字个数

第二行为n个整数num[i] (1 <= num[i] <= 1000000000)



输出描述:

在一行中输出所有可能是抹除掉的数,从小到大输出,用空格分割,行末无空格。如果没有可能的数,则输出mistake



输入例子:

2
3 6



输出例子:

mistake

个人思路:

我的整体思路就是,先对 n+1 数进行排序,然后从首尾数字入手进行一系列操作即可咯。
哇,就在刚才,我最终还是修改成功了呢。
之前重复的数字,加了一个判断
另外一个小问题就是必须是正整数
可以的,果然写博客不错哟

正确答案(本人&&牛客网 id:Cheeeenkun):

n = int(raw_input())
arr = [int(i) for i in raw_input().strip().split()]
ar = sorted(arr)
first = ar[0]
end = ar[n-1]
middle = n - 2
init = []
result = []
for i in range(first, end+1, 1):
init.append(i)
init_middle = len(init) - 2

if init_middle - middle > 1:
print 'mistake'
elif len(ar) != len(list(set(arr))):
print 'mistake'
else:
if ar == init:
a = ar[0] - 1
if a > 0:
result.append(str(a))
b = ar[n-1] + 1
if b > 0:
result.append(str(b))
else:
i = 0
j = 0
temp = sorted(ar[:])
while i < n and j < len(init):
if temp[i] != init[j]:
if init[j] > 0:
result.append(str(init[j]))
j += 1
else:
i += 1
j += 1
print ' '.join(result)
重复数字那里使用 list 和 set,自从会用了这两个好多问题解决起来很方便。
n = int(raw_input())
numbers_ = map(int,raw_input().split())
max_number = max(numbers_)
min_number = min(numbers_)
result = set(range(min_number,max_number+1))-set(numbers_)
if len(result) == 1:
print list(result)[0]
elif len(result) == 0:
if min_number-1 > 0:
print min_number-1,max_number+1
else:
print max_number+1
elif len(result) > 1:
print 'mistake'
这个 ce 大佬前面那题代码就很妙,哇!还是一个字,太妙了!
亮点在 result = set... 这一句,用 set 集合的关系!哇哇哇!膜拜吧

5.

如果一个数字能表示为p^q(^表示幂运算)且p为一个素数,q为大于1的正整数就称这个数叫做超级素数幂。现在给出一个正整数n,如果n是一个超级素数幂需要找出对应的p,q。 

输入描述:

输入一个正整数n(2 ≤ n ≤ 10^18)



输出描述:

如果n是一个超级素数幂则输出p,q,以空格分隔,行末无空格。
如果n不是超级素数幂,则输出No



输入例子:

27



输出例子:

3 3

个人思路:

这题我算是误打误撞,但还是 40 % case,因为数据太大,时间就超了,而且我只是一个求因子的过程,并没有判断素数
def yinshi(n):
y = []
i = 2
while i <= n :
if n % i == 0:
n = n / i
y.append(i)
else:
i += 1
return y

n = int(raw_input())
if len(list(set(yinshi(n)))) != 1:
print 'No'
else:
print list(set(yinshi(n)))[0], len(yinshi(n))
貌似是不是判断了素数,我时间也还是超时了。

分割线:
果然加了素数判断还是时间问题。

正确答案(牛客网 id:che.jianglin):

import math
n = int(raw_input())
l = int(math.log(n,2))
def isPrime(x):
if x<=1:
return False
for i in xrange(2,int(math.sqrt(x))+1):
if x%i==0:
return False
return True
# print(isPrime(3))
flag = True
for i in xrange(2,l+1):
p = math.pow(n,1.0/i)
if(p-int(p)==0 and isPrime(p)):
flag = False
print int(p),i
break;
if(flag):
print "No"
果然是数学问题,用了 log 对数函数,然后在用 pow 幂函数。
而我自己问题出在不应该用 while。

6.

给出一个正整数N和长度L,找出一段长度大于等于L的连续非负整数,他们的和恰好为N。答案可能有多个,我我们需要找出长度最小的那个。
例如 N = 18 L = 2:
5 + 6 + 7 = 18 
3 + 4 + 5 + 6 = 18
都是满足要求的,但是我们输出更短的 5 6 7


输入描述:

输入数据包括一行:
两个正整数N(1 ≤ N ≤ 1000000000),L(2 ≤ L ≤ 100)



输出描述:

从小到大输出这段连续非负整数,以空格分隔,行末无空格。如果没有这样的序列或者找出的序列长度大于100,则输出No



输入例子:

18 2



输出例子:

5 6 7

个人思路:

求 1 - N-1 的连续数列中,和等于 N 的长度最小数列
先从 L + 1 个长度计算,如果数列中有符合条件的值,则直接输出这个序列
否则的话, L ++ 继续求
那么,又是时间的问题


小的数字都可以完成要求,输入的数字如果太大,那么就不行。
arr = [int(i) for i in raw_input().strip().split()]
N = arr[0]
L = arr[1]
num = list(xrange(1, N+1))

j = 0
z = 1
k = L + z
add = sum(num[j:k])
while k < len(num):
if add == N:
break
else:
j += 1
k += 1
add = sum(num[j:k])

if k == len(num)-1:
z += 1
k = L + z
j = 0
add = sum(num[j:k])

if add != N or k-j > 100:
print 'No'
else:
m = map(str, num[j:k])
print ' '.join(m)
例如:
100 4

18 19 20 21 22
这都是可以完成的。
看到的另外一个思路:
等差数列求和:
S = (2*a1+n-1) / 2
a1 = 2 * S  + n - n^2 / 2 *n
n 从 L 到 100 找出满足的 a1,输出
嗯,总的来说,就是根据公式来求 a1,然后输出 a1 之后的 i 即 L 位
哇,我记得当时貌似是有想到等差数列,结果没太深入想。

正确答案(牛客网 id:Panzerfaust):

import math
import sys
def judge(m,n):
for i in range(n,101):
start = int((2*m/i-i+1)/2)
if int((start+start+i-1)*i/2) == m:
return ' '.join([str(var) for var in range(start,start+i)])
return "No"

for line in sys.stdin:
a = [int(var) for var in line.split()]
print(judge(a[0],a[1]))
start = a1

7.

牛牛新买了一本算法书,算法书一共有n页,页码从1到n。牛牛于是想了一个算法题目:在这本算法书页码中0~9每个数字分别出现了多少次? 

输入描述:

输入包括一个整数n(1 ≤ n ≤ 1,000,000,000)



输出描述:

输出包括一行10个整数,即0~9这些数字在页码中出现的次数,以空格分隔。行末无空格。



输入例子:

999



输出例子:

189 300 300 300 300 300 300 300 300 300

个人思路:

不得不说,这一题我又是被大整数搞蹦了。而我完全没想到这样的算法来解决此题, 我只用了偷鸡的方法。
dic = {'1': 0, '2': 0, '3': 0, '4': 0, '5': 0, '6': 0, '7': 0, '8': 0, '9': 0, '0': 0}
page = int(raw_input())
arr = list(xrange(1, page+1))
for a in arr:
num = list(str(a))
for n in num:
dic
+= 1
print dic['0'], dic['1'], dic['2'], dic['3'], dic['4'], dic['5'], dic['6'], dic['7'], dic['8'], dic['9']
和算法相比,我真特么会选方法。
会个P啊会。

正确答案(牛客网 id:zero_python):

num = int(raw_input())

def find(num):
# 计算每个数字, 在每一位上出现的次数.
res = [0] * 10
digit = 1  # 个位
while True:
low = num % digit
cur = (num % (10 * digit)) / digit
high = num / (10 * digit)

if cur == 0 and high == 0:
break
# 各个数字在digit位上出现了几次?

for i in range(10):
if i < cur:
if i == 0:
res[i] += high * digit
else:
res[i] += (high+1) * digit
elif i == cur:
if i==0:
res[i] += (high-1) * digit + low + 1
else:
res[i] += high * digit + low + 1
else:
if i == 0:
res[i] += (high-1) * digit
else:
res[i] += high * digit
digit *= 10  # 下一位
return res

res = find(num)
print ' '.join(map(str, res))
给大家提供一种思路(牛客网 Id: 天祺):

2位数的情况:

N=13,个位数出现的1的次数为2,分别为1和11,十位数出现1的次数为4,分别为10,11,12,13,所以f(N) = 2+4。

N=23,个位数出现的1的次数为3,分别为1,11,21,十位数出现1的次数为10,分别为10~19,f(N)=3+10。

由此我们发现,个位数出现1的次数不仅和个位数有关,和十位数也有关,如果个位数大于等于1,则个位数出现1的次数为十位数的数字加1;如果个位数为0,个位数出现1的次数等于十位数数字。而十位数上出现1的次数也不仅和十位数相关,也和个位数相关:如果十位数字等于1,则十位数上出现1的次数为个位数的数字加1,假如十位数大于1,则十位数上出现1的次数为10。

3位数的情况:

N=123

个位出现1的个数为13:1,11,21,…,91,101,111,121

十位出现1的个数为20:10~19,110~119

百位出现1的个数为24:100~123

我们可以继续分析4位数,5位数,推导出下面一般情况:

假设N,我们要计算百位上出现1的次数,将由三部分决定:百位上的数字,百位以上的数字,百位一下的数字。

如果百位上的数字为0,则百位上出现1的次数仅由更高位决定,比如12013,百位出现1的情况为100~199,1100~1199,2100~2199,…,11100~11199,共1200个。等于更高位数字乘以当前位数,即12 * 100。

如果百位上的数字大于1,则百位上出现1的次数仅由更高位决定,比如12213,百位出现1的情况为100~199,1100~1199,2100~2199,…,11100~11199,12100~12199共1300个。等于更高位数字加1乘以当前位数,即(12 + 1)*100。


如果百位上的数字为1,则百位上出现1的次数不仅受更高位影响,还受低位影响。例如12113,受高位影响出现1的情况:100~199,1100~1199,2100~2199,…,11100~11199,共1200个,但它还受低位影响,出现1的情况是12100~12113,共14个,等于低位数字13+1。

8.

牛牛正在挑战一款名为01翻转的游戏。游戏初始有A个0,B个1,牛牛的目标就是把所有的值都变为1,每次操作牛牛可以任意选择恰好K个数字,并将这K个数字的值进行翻转(0变为1,1变为0)。牛牛如果使用最少的操作次数完成这个游戏就可以获得奖品,牛牛想知道最少的操作次数是多少?
例如:A = 4 B = 0 K = 3 
0000 -> 1110 -> 1001 -> 0100 -> 1111 
需要的最少操作次数为4 

输入描述:

输入为一行:
一共三个整数A(0 ≤ A ≤ 100,000),B(0 ≤ B ≤ 100,000),K(1 ≤ K ≤100,000).以空格分隔



输出描述:

输出一个整数,表示最少需要的操作次数。如果不能完成,则输出-1



输入例子:

4 0 3



输出例子:

4

个人思路:

给你说,现在就算是手写,笔算,自己下去画,我都不知道怎样翻转,你还让我编程解决。毫无思路。

正确答案(牛客网 id:TinyJian):

本人比较喜欢数学,就从数学的角度来解这道题吧

设 n = A+B

设 位置值序列集合 E = {e1, e2,
e3,... en},
ei ∈ {0, 1},其中ei表示第i个位置上的值
(1 ≤ i ≤ n)

假设初始时,前面A个位置为0,后面B个位置为1

设 Ti 为 第i个位置上翻转的次数

因为一次翻转必翻转K个位置,假设进行了X次翻转(未知数),则有以下等式

① XK = ∑Ti (1 ≤ i ≤ n)

因为同一个位置翻转2次得到是原来的值,所以为了使所有位置均为1, Ti 必满足以下条件:

② Ti = 1 + 2Si (ei 初始为0)

③ Ti = 2Si(ei 初始为1)

其中Si 表示第i个位置进行了 Si次2次翻转

结合①、②、③可得:

④ XK = A + 2 ∑Si (1 ≤ i ≤ n)

⑤ XK - A 必为偶数

我对此的理解为,总的来看:在某些位置上进行了2次翻转,和A个位置的1次翻转,就全部为1了。

对 ∑Si 观察可得:

对于初始为1的位置,2次翻转次数不能超过X/2

对于初始为0的位置,2次翻转次数不能超过(X-1)/2 ,因为最后一次翻转不能属于“2次翻转”中的一次翻转

我们假设所有位置的2次翻转次数都达到最大,则有不等式:

⑥ (XK - A)/2 = ∑Si (1 ≤ i ≤ n)≤
A ((X-1)/2) + B(X/2)

满足⑤、⑥条件X即可满足题意

我们可以相信,X不能大于 A的最大值+B的最大值 = 200000

PS:我也喜欢数学((┬_┬))
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: