2019腾讯暑期实习常规批笔试技术研究与数据分析卷编程题

这篇博客详细解析了2019年腾讯暑期实习笔试的技术题目,包括数字拆分问题、水果运费计算以及找最小数的算法。文章通过解题思路、注意点、解析和Python实现,帮助读者理解并解决这三道编程题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题一 数字拆分

一个数字有两种操作,1 对所有数字减一 2 把所有数字都拆分成两个更小的数之和,问最多拆分K次,把N完全消去最少需要多少轮操作。

输入取值范围: 1<= N <=100, 0<=K<=100

样例: 输入 5 2 ,输出 4。 输入15 4,输出 6

注:这里其实第二个用例错了, 因为5次就能完全消去。

解题思路

注意点

  1. 拆分操作是所有数字拆分,减一也是所有数都减。
  2. 把N完全消去最少需要多少轮操作。(废话)

解析

  1. 因为是所有数字同时拆分且所有数字同时减1,所以达到完全消去只需要保留过程中最大的数字即可,不需要完全模拟。
  2. 因为反正都是要消去,但是要找最少操作次数我们要比较这次消去前要不要拆分比较好。

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

解题思路

注意点

  1. 一条笔直的公路有n个村庄。
  2. 把k个水果搬到相邻村庄需要k块钱的运费
  3. 所有村庄供需平衡

解析

  1. 表示所有村庄在同一维度上,没有复杂的两两关系,降低问题难度。
  2. 从贪心的角度上,若从左往右考虑,最左的需求村庄从最左的供应村庄进货肯定会是全局最优解,因为最左的供应村庄往更右的需求村庄运水果会有更高的运费。
  3. 比如从左向右考虑,前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<=105 数组中所有的数字ai满足1<=ai<=109

样例:
输入

4 1
5 5 7 2

输出

2

输入

2 2
4 6

输出

4
2

解题思路

注意点

  1. 找出数组中最小非0数字X。
  2. 把数组中的所有非零数字减去X。
  3. 这个数组进行K次如下的操作。

解析

  1. 只找最小的非零数字。
  2. 为0的数字永远为0了。大小顺序不变。
  3. 只进行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。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值