利用全排列解决LeetCode第3343题“统计平衡排列的数目”问题
3343.统计平衡排列的数目
难度:困难
问题描述:
给你一个字符串num。如果一个数字字符串的奇数位下标的数字之和与偶数位下标的数字之和相等,那么我们称这个数字字符串是平衡的。
请你返回num不同排列中,平衡字符串的数目。
由于答案可能很大,请你将答案对109+7取余后返回。
一个字符串的排列指的是将字符串中的字符打乱顺序后连接得到的字符串。
示例1:
输入:num="123"
输出:2
解释:
num的不同排列包括:"123","132","213","231","312"和"321"。
它们之中,"132"和"231"是平衡的。所以答案为2。
示例2:
输入:num="112"
输出:1
解释:
num的不同排列包括:"112","121"和"211"。
只有"121"是平衡的。所以答案为1。
示例3:
输入:num="12345"
输出:0
解释:
num的所有排列都是不平衡的。所以答案为0。
提示:
2<=num.length<=80
num中的字符只包含数字'0'到'9'。
问题分析及解决思路:
根据问题的描述,解决问题分为这样几个步骤:
1、首先是如何判定一个数字字符串num是否为平衡字符串?为此编写函数checkBalance(num)实现这一功能,如果num是平衡字符串,返回True,否则返回False。
2、其次是如何生成num数字字符串的全排列?为此设计两个函数来解决这个问题。
(1)函数listone(n,num)有两个参数,n是一个数字字符,num是一个数字字符串,其功能是将数字字符n与num形成全排列,比如字符“2”和数字字符串“345”,可以形成“2345”、“3245”、“3425”、“3452”共4种形式的全排列组合并返回。
(2)函数listall(num)则利用递归的方法形成num数字字符串的全排列,并返回一全排列的字符串列表。
3、对生成的num全排列要进行去重处理,根据示例中的数据,num中的数字可以重复,比如“112”,所以生成的全排列当中有重复的字符串。
4、最后对去重之后的排列字符串依次进行平衡字符串检测并计数,最后输出统计出来的总数,问题即得到解决。
程序如下:
#判断一个数字字符串是否为平衡字符串
def checkBalance(num):
num=list(map(int,list(num)))
o=sum(num[::2])
j=sum(num[1::2])
return o==j
#数字n插入到num数字字符串形成的全排列
def listone(n,num):
num=list(num)
a=[]
for i in range(len(num)+1):
b=num[0:i]+[n]+num[i:]
b=''.join(b)
a.append(b)
return a
#生成num数字字符串的全排列
def listall(num):
if len(num)==2:
return listone(num[0],num[1])
else:
b=[]
for i in listall(num[1:]):
b=b+listone(num[0],i)
return b
# 统计共有多少种平衡排列数
#输入原始数字字符串
num=input('pls input num=')
#对生成的num全排列进行去重处理
a=set(listall(num))
#输出去重之后的全排列
print('去重之后的全排列:',a)
#统计平衡排列数目
c=0
for i in a:
if checkBalance(i):
c=c+1
#输出平衡排列数目
print('统计出的平衡排列数目:',c)
运行实例一
pls input num=1234
去重之后的全排列: {'4231', '4132', '1324', '2143', '1243', '2341', '4213', '2314', '4123', '1342', '2431', '1423', '1234', '4321', '2413', '3124', '3142', '1432', '3412', '4312', '2134', '3241', '3214', '3421'}
统计出的平衡排列数目: 8
运行实例二
pls input num=3333
去重之后的全排列: {'3333'}
统计出的平衡排列数目: 1
运行实例三
pls input num=112
去重之后的全排列: {'112', '121', '211'}
统计出的平衡排列数目: 1
感悟:
全排列的生成是解决很多问题的关键,应注意总结各种生成全排列的方法。