Three sum 问题及其 python 实现

3-sum 问题

给定一个整数 x 和一个由整数构成的集合 S,从 S 中找一 个由三个元素构成的子集,该子集中的三个元素之和必须等于 x。使用穷举法列举 S 的所有 由三个元素构成的子集,逐个检查其是否满足条件。

穷举法

最容易想到的就是穷举法了,事实上,我们很容易写出subset-sum 问题(求出全部集合S的任意长度的和为给定常数x的子集)的算法

# input S , x
n = len(S) 
for i in range(1, 2 ** n): 	
	T = [] 
	for j in range(n): 
		if (i >> j) % 2 == 1: T.append(S[j])  
	if sum(T) == x: 
	print(T, end = ' ') 

复杂度为 O ( a n ) O(a^n) O(an)

稍微修改一下,容易得到3-sum 问题。

# input S , x.
n = len(S) 
for i in range(1, 2 ** n): 	
	T = [] 
	for j in range(n): 
		if (i >> j) % 2 == 1: T.append(S[j])  
		if len(T) == 3: break
	if sum(T) == x: 
	print(T, end = ' ') 
	# [73, 6, 5, 51] [21, 77, 5, 32]

当然,没有奇葩会这么干(冗余操作太多了,我们生成了 1 ∼ 2 n − 1 1\sim2^n-1 12n1的所有数,然后选取其中二进制有三个1的数,并检验集合中对应数字的和是否为x……)
正常的穷举法,应该是三个for循环

# input S , x.
n = len(S) 
T = []
for i in range(0, n): 	
	for j in range(i+1, n):
		for k in range(j+1, n):
			if S[i]+S[j]+S[k] = x:
				 T.append([S[i],S[j],S[k]])
print(T)				 

时间复杂度为 O ( n 3 ) O(n^3) O(n3)

算法优化

我们尝试对穷举法进行优化。

假定存在一个子集 {a, b, c} 满足 x = a + b + c。原问题可以转换为另一个问 题:对于 S 中的任意两个元素 b 和 c,在 S − {b, c} 中查找一个等于 x − b − c 的元素。为了提高查找的效率,可以先将所有元素按照从小到大的顺序排序,然后使用二分查找。如此下来,时间复杂度为 O ( n 2 log ⁡ n ) O(n^2\log n) O(n2logn)

def bisect(list,target,j):
	low, high = j,len(list)-1
	while low<=high:
		mid = (low + high)//2
		if list[mid] == target :
			return True
		elif list[mid] < target: 
			low = mid + 1
		elif list[mid] > target:
			high = mid-1
	return False
		
S = input("set:").split(",")
S = list(map(int,S))
x = int(input("target:"))
S.sort()
n = len(S)
T = []
for i in range(0, n): 	
	for j in range(i+1, n):
		if bisect(S,x-S[i]-S[j],j):
			T.append([S[i],S[j],x-S[i]-S[j]])
print(T)
  • 21
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值