文章转自 男票的博客 哈哈哈!并以通俗的语法复述~
Together_CZ的博客
种一棵树,最好的时间是十年前,其次是现在
每天学习哥哥一小步 大家可以跟着我一起学习~一大步
有问题问我 ==
python实现将给定列表划分为(等长的/不等长)的元素和大致相等的两个子列表
问题很简单:给定一个列表,元素都是数值类型的有序无序不知道,这个其实无所谓的,需要将这个列表划分为两个等长的子列表使得他们的绝对值之差能够最小化,这个问题仔细一想很简单,可以分析一下:假设最后得到的两个列表元素分别为:
列表A: a1+a2+....+an
列表B: b1+b2+...+bn
那么什么情况下会有sum(A)-sum(B)最小呢?
我们之前都学过等差序列、等比序列相关的内容,这里不需要这些知识,只是借鉴了思想,想一下:我在这里假设我对A、B中的元素已经排好序了,默认升序,那么:是不是只要(b1-a1)+(b2-a2)+...+(bn-an)最小就行了呢?答案是:肯定的!
想要这样就需要保证每一个(an-bn)都是最小的,这样的话也很简单就是每次保证an和bn分别为数组中最大的两个数字就行了,做法很简单就是最开始将最大的数字放入A中,弹出最大的数字后,将剩余数组中最大的数字加入到B中,同样弹出,接下来的操作需要相反,即将最大的元素放入B中,同样弹出后,将剩余数组最大的元素放入A中同样弹出.......
循环进行下去直至列表为空即可。
下面是具体的实现:
#!usr/bin/env python
#encoding:utf-8
'''
__Author__:沂水寒城
功能:将给定的列表划分为(等长的)元素和大致相当的两个列表
'''
def test_func1(one_list):
'''
将给定的列表划分为等长的元素和大致相当的两个列表
'''
num_list=sorted(one_list[:])
first_list=[]
second_list=[]
first_list.append(num_list.pop(-1))
second_list.append(num_list.pop(-1))
while len(num_list):
second_list.append(num_list.pop(-1))
first_list.append(num_list.pop(-1))
return first_list, second_list
if __name__ == '__main__':
list1=[3,6,9,0,2,14,56,89]
list2=[6,9,23,56,12,3,7,36]
print '*******************将给定的列表划分为等长的元素和大致相当的两个列表************************'
print test_func1(list1)
print test_func1(list2)
结果如下:
*******************将给定的列表划分为等长的元素和大致相当的两个列表************************
([89, 9, 3, 0], [56, 14, 6, 2])
([56, 12, 7, 3], [36, 23, 9, 6])
接下来需要想一个问题:如果说修改一下题目,变为更实际的问题,因为现实中往往情况并不会这么恰到好处,比如一个任务特别特别大以至于超过了总任务执行时间的一般,那么显然上面的划分并不是最优的,那么就需要考虑改变一些条件了。
将给定的列表划分为元素和大致相当的两个列表,这里不再要求等长了怎么办呢?其实:方法同源解决的思路是一样的,只是需要在划分完之后加上一下限制修饰的操作即可。在得到两个划分之后的列表之后开始循环的判断,如果元素和较大的列表与元素和较小的列表的差值大于元素和较大列表中的最小元素的时候,需要弹出最小元素加入的元素和较小列表当中,重复此操作,直至不满足条件为止。
def test_func2(one_list):
'''
将给定的列表划分为元素和大致相当的两个列表
'''
num_list=sorted(one_list[:])
first_list=[]
second_list=[]
first_list.append(num_list.pop(-1))
second_list.append(num_list.pop(-1))
while len(num_list):
second_list.append(num_list.pop(-1))
first_list.append(num_list.pop(-1))
while sum(first_list)-sum(second_list)>min(first_list):
second_list.append(first_list.pop(first_list.index(min(first_list))))
return first_list, second_list
结果如下:
*******************将给定的列表划分为元素和大致相当的两个列表************************
([89], [56, 14, 6, 2, 0, 3, 9])
([56, 12, 7], [36, 23, 9, 6, 3])
完整的实现如下:
#!usr/bin/env python
#encoding:utf-8
'''
__Author__:沂水寒城
功能:将给定的列表划分为(等长的)元素和大致相当的两个列表
'''
def test_func1(one_list):
'''
将给定的列表划分为等长的元素和大致相当的两个列表
'''
num_list=sorted(one_list[:])
first_list=[]
second_list=[]
first_list.append(num_list.pop(-1))
second_list.append(num_list.pop(-1))
while len(num_list):
second_list.append(num_list.pop(-1))
first_list.append(num_list.pop(-1))
return first_list, second_list
def test_func2(one_list):
'''
将给定的列表划分为元素和大致相当的两个列表
'''
num_list=sorted(one_list[:])
first_list=[]
second_list=[]
first_list.append(num_list.pop(-1))
second_list.append(num_list.pop(-1))
while len(num_list):
second_list.append(num_list.pop(-1))
first_list.append(num_list.pop(-1))
while sum(first_list)-sum(second_list)>min(first_list):
second_list.append(first_list.pop(first_list.index(min(first_list))))
return first_list, second_list
if __name__ == '__main__':
list1=[3,6,9,0,2,14,56,89]
list2=[6,9,23,56,12,3,7,36]
list3=[1345,234,56,78,90,4,1,56,78,4,456,77]
print '*******************将给定的列表划分为等长的元素和大致相当的两个列表************************'
print test_func1(list1)
print test_func1(list2)
print test_func1(list3)
print '*******************将给定的列表划分为元素和大致相当的两个列表************************'
print test_func2(list1)
print test_func2(list2)
print test_func2(list3)
结果如下:
*******************将给定的列表划分为等长的元素和大致相当的两个列表************************
([89, 9, 3, 0], [56, 14, 6, 2])
([56, 12, 7, 3], [36, 23, 9, 6])
([1345, 90, 78, 56, 4, 1], [456, 234, 78, 77, 56, 4])
*******************将给定的列表划分为元素和大致相当的两个列表************************
([89], [56, 14, 6, 2, 0, 3, 9])
([56, 12, 7], [36, 23, 9, 6, 3])
([1345], [456, 234, 78, 77, 56, 4, 1, 4, 56, 78, 90])
这里需要指出来的是:划分为等长的列表的前提是:列表长度必须是偶数的不然没有意义,当然如果非要使用奇数长度的列表的话可以采用补充“0”的方法使其变为偶数,不影响最后的结果,程序中没有添加这个判断,需要的话可以自行添加。