python中两列表,任意交换元素,使差值最小

上课老师出了一道题,任意交换两个列表的元素,使差值最小,是一道华为的面试题。

我想不出来, 百度了一下,本质上,是背包问题的一个变种,然后我看懂了背包问题的原理,并阅读了别人的C++代码,然后按照自己的理解,写出了Python的代码。

关于背包问题的理解,我推荐一个作者,写的极好,我就是在这篇文章的指导下,花了5个小时,理解的。写出我理解的时间,是给那些看了1个小时,就垂头丧气的人,一点信心,坚持住,一定能理解的。

很多人或许会觉得理解这道题,话这么久不值得,而我认为,虽然这道题我花了5个小时,但是下一次,再遇到同等难度的题,我只要一两个小时了,这是逻辑上的提升,终生受用。

https://blog.csdn.net/xp731574722/article/details/70766804

再说说我理解上的瓶颈,m[ i ][ j ] = m[ i - 1][ j - w[ i ] ] + v [ i ],这句话理解时,一定要把m[ i - 1][ j - w[ i ] ]的意思读出来,大声读出来,叫做面对第 i-1 个变量时,容量为 j - w[ i ]的背包,所有拥有的最大价值。

"""
整体思路:
要使两个列表的差最小,也就是两个列表最接近;
首先,将两个列表合并为一个列表li,总值为sum;
从li中取出一些元素,组成表li1,保证sum(li1)的值最接近sum/2,剩下元素组成列表li2,这样
sum(li2)也最接近sum/2,这样就使得两个表最接近;
"""
li1, li2 = [1,2,3,4,5,6,7,9], [2,3,4,5,6,10]
li = li1 + li2
# 在开头加一个0,保持索引的对应性,即索引为1时,拿到的是第一个元素
li.insert(0,0)
# 求得两个表的总值
SUM = sum(li1) + sum(li2)
# c为待接近的sum/2的值,这里用int,因为列表里全是整数,小数没有意义
# 列表里总元素个数为n,这里没有算上插入的0
c = int(SUM/2)
n = len(li)-1

# li1最开始的容量为sum/2,每加入一个元素,容量要减去对应的值
# 建立一个二层列表,m[i][j]表示,面对li中第i个元素,容量为j时,可以取得的最大值
m = []
for i in range(n+1):
    m.append([])
    for j in range(c+1):
        m[i].append(0)

# 面对第i个元素
# 容量j<li[i]时,无法放入该元素,只能选择不放,m[i][j] = m[i-1][j]
# 容量j>li[i]时,可以考虑是否放入该元素
# 如果放入,则 m[i][j] = m[i-1][j - li[i]] + li[i]
# 如果不放入,则 m[i][j] = m[i-1][j]
# 根据m的特性,选择其中较大的那一个 max(m[i-1][j], m[i-1][j-li[i]] + li[i])
for i in range(1,n+1):
    for j in range(1,c+1):
        if j >= li[i]:
            m[i][j] = max(m[i-1][j], m[i-1][j-li[i]] + li[i])
        else:
            m[i][j] = m[i-1][j]

# 需要根据m[n][c]回溯,寻找li1中取了哪些元素
# x: 如果第i个元素放入了li1,则x[i] = 1,否则x[i] = 0
# y: 是一个从n 到 0 的序列,用于回溯
# w: w是c的复制,保持不修改原c
x, y ,w =  [], [], c
for i in range(n+1):
    x.append(0)
    y.append(i)
y.reverse()
for i in y:
    if m[i][w] == m[i-1][w]:
        x[i] = 0
    else:
        x[i] = 1
        w -= li[i]

# 将对应的元素加入li1表和li2表,并打印结果
li1 = []
li2 = []
for i in range(1, n+1):
    if x[i] == 1:
        li1.append(li[i])
    else:
        li2.append(li[i])
print(li1)
print(sum(li1))
print(li2)
print(sum(li2))

 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值