经典面试题:数字拆分消减问题与单链路村庄销售代价问题[python]

本文探讨了两个算法问题:数字拆分消减问题与单链路村庄销售代价问题。数字拆分消减问题的目标是在有限次数内通过拆分与消减操作,将数字序列变为全0序列;而单链路村庄销售代价问题则是计算在一条直线上分布的村庄间完成水果买卖所需的最小运输代价。

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


数字拆分消减问题

题目

给出两个数字 n , k n,k n,k ( n , k ∈ N + n,k \in \N^+ n,kN+)。
n n n是需要拆分消减的数字序列(初始情况序列仅包含一个数字), k k k是最多可拆分的次数,其中:

  • 拆分是指将一个数字的拆分序列中的每个数字 a a a拆分成两个正整数 a 1 a_1 a1 a 2 a_2 a2 a 1 + a 2 = a a_1+a_2=a a1+a2=a
  • 效减是秩将所有拆分得到的数字减去1;

e.g : 对数字序列[7]先拆分两次再消减一次——第一次拆分得到[4, 3]、第二次拆分得到[2, 2, 1, 2],消减后得到[1, 1, 0, 1]。
问:输入 n , k n,k n,k,请输出能把序列变为全0序列的最少次数。

分析

  1. 要使得其最快为0,显然应进行尽量多的平均拆分再进行消减。由于数字2先拆分后消减与先消减再拆分到0都需要2步,因此平均到数列中出现2即可停止。
  2. 在任意一次平均拆分结束后,如果出现奇数,则意味着下一次拆分必然会出现 a a a a + 1 a+1 a+1的情况,如[14]拆为[7 7],再拆为[3 4 3 4],若此时拆分结束,至少还需要4次消减才能将其降为0。即拆分完毕后的消减次数为:
  • 若出现奇数:消减次数 = m i n + 1 min+1 min+1( m i n min min是拆分得到的序列最小值)
  • 若未出现奇数或本身未进行拆分:消减次数 = m i n min min

代码

is_odd = lambda x: x % 2 == 1

for nk in nk_list:
    n, k = nk[0], nk[1]
    _min = n  #
    found_odd = is_odd(n)
    divide_done = 0  # 拆分进行次数
    for _ in range(k):
        if _min <= 2:
            break
        found_odd = is_odd(_min)
        _min = _min // 2
        divide_done += 1

    if divide_done > 0 and found_odd:
        _min += 1

    print(divide_done+_min)

测试数据:

# 输入数据
# 输出应为 0 1 1 2 2 5 6 16 8
nk_list = [[0, 7], [1, 0], [1, 2], [2, 1], [2, 3], [15, 3], [16, 2], [100, 3], [100, 7]]

单链路村庄销售代价问题

题目

在一条直线公路上,等距分布 n n n个村庄(n为大于1的自然数),第 i i i个村庄有 s i s_i si的水果要销售或购入,当 s i &lt; 0 s_i&lt;0 si<0则意味着要购入 s i s_i si个水果,当 s i &gt; 0 s_i&gt;0 si>0则意味着要卖出 s i s_i si个水果。已知每个水果每向旁别的存在运输一次,就产生 1 1 1个单位的代价。先给出一组数据,保证整条公路上的水果供求关系的和为0,问要使每个村庄完成购入/卖出指标,最小代价为多少。
e.g 例如输入[1, 0, -1],则最小代价为 4 4 4

分析

由于所有村庄等距分布在一条公路上,因此当我们从左往右遍历数组,会发现无论左边是正是负,必然需要被“抹平”。

  • 假设有这么一个堆(heap),存放着“水果债卷”,一个商人从走往右走,对这个堆进行分配和移动。
  • 每到一个村庄,商人先按照供需关系修改堆中的债券关系,如果 s i &gt; 0 s_i&gt;0 si>0,则堆中债券变多,否则变少。
  • 随后,商人根据债卷的价值产生移动水果的代价。如果 s i &gt; 0 s_i&gt;0 si>0,则意味着左边有数量为 s i s_i si的水果要移动到右边,否则意味着右边有数量为 s i s_i si的水果要移动到左边。
  • 无论向左还是向右移动,最终都会产生 a b s ( h e a p ) abs(heap) abs(heap)的代价。

代码

def count(data):
    heap, cost = 0, 0
    for i in data:
        heap += i
        cost += abs(heap)
    return cost

测试:

s1 = [1, -1, 2, 0, -2, -4, 1, 3]  # 12
s2 = [-1, -2, -3, 0, 1, 2, 3]  # 24
s3 = [1, 2, 3, 0, -1, -2, -3]  # 24
s4 = [1, -1, 0]  # 1
s5 = [-1, 1, 0]  # 1
s6 = [2, 0, -2]  # 4

print(count(s1))
print(count(s2))
print(count(s3))
print(count(s4))
print(count(s5))
print(count(s6))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值