腾讯暑期实习常规批笔试技术研究与数据分析卷编程题
2019腾讯暑期实习常规批笔试技术研究与数据分析卷编程题
- 题一 数字拆分
-
- 解题思路
-
- 注意点
- 解析
- python实现
- 代码解释
- 题二 水果运费
-
- 解题思路
-
- 注意点
- 解析
- python实现
- 代码解释
- 题三 找最小数
-
- 解题思路
-
- 注意点
- 解析
- python实现
- 代码解释
题一 数字拆分
一个数字有两种操作,1 对所有数字减一 2 把所有数字都拆分成两个更小的数之和,问最多拆分K次,把N完全消去最少需要多少轮操作。
输入取值范围: 1<= N <=100, 0<=K<=100
样例: 输入 5 2 ,输出 4。 输入15 4,输出 6
注:这里其实第二个用例错了, 因为5次就能完全消去。
解题思路
注意点
- 拆分操作是 所有 数字拆分,减一也是 所有 数都减。
- ~~把N完全消去 最少 需要多少轮操作。(废话) ~~
解析
- 因为是所有数字同时拆分且所有数字同时减1,所以达到完全消去只需要保留过程中最大的数字即可,不需要完全模拟。
- 因为反正都是要消去,但是要找 最少 操作次数我们要比较这次消去前要不要拆分比较好。
python实现
# -*- coding: utf-8 -*-
"""
Created on Sun Apr 7 20:28:10 2019
@author: Ang
"""
def f(a, k):
if k==0:
return a
a1 = a
if a%2==0:
a = a/2
else:
a = a//2+1
a2 = f(a,k-1)+1
return a1 if a1<a2 else a2
x = list(map(int,input().split(' ')))
a = x[0]
k = x[1]
print(int(f(a,k)))
代码解释
f(a,k) 表示数字a在k次拆分机会的条件下最少需要几次能被完全消去。
若不拆分直接消去 ,则为方案一的答案a1,为a次操作。
若拆分再接着消去 ,则为方案二的答案a2,我们先把a拆分,且为了消去操作次数最小肯定是对半拆分,保留 最大
的数字b即可,计算方案二的拆分次数f(b,k-1)+1。
两种方案选择最小的操作次数返回。
题二 水果运费
一条笔直的公路上有n个村庄,每个村庄有A[i]个水果,A[i] >0 代表 村庄需要购进水果, A[i] < 0 代表村庄需要卖出水果。
所有村庄供需平衡,即所有A[i]求和为0,把k个水果搬到相邻村庄需要k块钱的运费,
最少需要多少花费可以满足所有村庄对水果的需求。
输入取值范围: 2 <= n <= 300000, -1000 <= A[i] <= 1000
样例:
输入
5
5 -4 1 -3 1
输出
9
解题思路
注意点
- 一条笔直的公路 有n个村庄。
- 把k个水果搬到 相邻 村庄需要k块钱的运费
- 所有村庄 供需平衡 。
解析
- 表示所有村庄在同一维度上,没有复杂的两两关系,降低问题难度。
- 从贪心的角度上,若从左往右考虑,最左的需求村庄从最左的供应村庄进货肯定会是全局最优解,因为最左的供应村庄往更右的需求村庄运水果会有更高的运费。
- 比如从左向右考虑,前i个村庄的供需若不平衡,肯定会继续向右运水果或进水果而 产生更多费用 ,若平衡则 不产生更多费用 。所以我们只需要从左往右或从右往左把运费理一遍即可。
python实现
# -*- coding: utf-8 -*-
"""
Created on Sun Apr 7 20:51:03 2019
@author: Ang
"""
N = eval(input())
x = list(map(int,input().split(' ')))
ans = x[0]
for i in range(1,N):
x[i] += x[i-1]
ans += abs(x[i])
print(ans)
代码解释
x[i] 表示要平衡前i个村庄的供需,还要供/需多少水果(其绝对值就是运费)。
就从头到尾从左到右把运费理一遍即可。
注:这是我下来后才整理出来更简单的方法,当时我的做法是给了两个index(i,j),i表示最左的还需要水果的村庄,j表示最左的还可以提供水果的村庄,从左往右满足需求的理了一遍运费,也是AC。
下来整理的这个方法当时有点灵感但是写出来一个错误的,当时为了找出错误在哪浪费了大量时间导致很简单的第三题没有时间完成。太傻了
题三 找最小数
一天,小Q得到了一个包含n个数字的数组,他想对这个数组进行K次如下的操作。首先找出数组中最小的非0数字X,输出它,然后把数组中的所有非零数字都减去X;如果数组中的数字都是0,那么直接输出0。
输入描述
第一行两个数字n和k,用一个空格分隔
第二行n个数字,每两个数字之间用一个空格分隔
满足1<=n,k<=10 5 数组中所有的数字ai满足1<=ai<=10 9
样例:
输入
4 1
5 5 7 2
输出
2
输入
2 2
4 6
输出
4
2
解题思路
注意点
- 找出数组中 最小 的 非0 数字X。
- 把数组中的所有 非零 数字 都 减去X。
- 这个数组 进行K次 如下的操作。
解析
- 只找最小的非零数字。
- 为0的数字永远为0了。大小顺序不变。
- 只进行k次。意味着我们排序后,只需要对前面的部分数字进行处理,不需要全部处理。
python实现
# -*- coding: utf-8 -*-
"""
Created on Sun Apr 7 21:16:43 2019
@author: Ang
"""
x = list(map(int,input().split(' ')))
n = x[0]
k = x[1]
A = list(map(int,input().split(' ')))
def f():
global A
global k
A.sort()
i = 0
s = 0
while k:
while A[i]==s:
i+=1
if i>=n:
return
print(A[i]-s)
s+=(A[i]-s)
k-=1
f()
for i in range(k):
print(0)
代码解释
首先我们把list A进行从小到大排序。
i 表示当前考虑的数字。 s 表示当前已减去的数字和。
只需要考虑当前A[i]是不是等于s即可,若 等于 ,表示A[i]已被减到0;否则输出 A[i]-s 即可。不用实际的把所有数都减一遍。
若i超过了n(数字总个数),表示已经没有更小的非0数字了,需要补剩余轮次的0。