我的目标是找到4到666554之间的所有数字的总和,其中包括4,5,6且满足以下约束条件。
数字出现次数的约束
时间数6出现在数字< = 3
中SUM = 4 + 5 + 6 + 45 + 46 + 54 + 55 + 56 + 64 + 65 + 66 + 454 + 455 + ................... .. + 666554。
简单的方法是运行循环并添加由4,5和6组成的数字,这些数字满足上述约束条件。
long long sum = 0;
for(int i=4;i <=666554;i++){
/*check if number contains only 4,5 and 6 and constraints are not violated
if condition is true then add the number to the sum*/
}
但似乎效率低下。检查号码是由4,5和6组成 并且数字不违反约束需要时间。有没有办法提高效率。我已经尝试了很多,但没有找到新的方法。请帮助。
答案 0 :(得分:3)
你应该只检查由数字4,5和6组成的数字,其中只有几百个。
这并不太难:在你的循环中,不要只是将i增加1.
如果i%10&lt; 6然后你只需将我增加1.
否则,减去2(例如646变为644,6变成4);如果我&lt; 10然后加40,你完成了,如果我%100&lt; 60然后将我增加10,你就完成了。
否则,减去20(例如5466变为5464然后5444);如果我&lt; 100然后添加400,你就完成了,如果i%1000&lt; 600然后只增加100我就完成了。
依此类推。这样,你不会检查大约600,000个数字,但只检查大约800个。
更好的方法是找不到数字。我们来看看六位数字。数字4可以位于六个位置。数字5可以在(5 * 4)/ 2 = 10个位置,数字6必须在其余位置。因此,只有60个数字,包含60位数字4,120位数字5,180位数字6.每个数字在所有位置都会出现,因此总和为10 * 444444 + 20 * 555555 + 30 * 666666.您执行类似的计算1 .. 5位数。
答案 1 :(得分:2)
我认为生成所有这些数字的最简单方法是(通常是,当您需要迭代某些组合对象时)以递归方式迭代它们。写一个递归函数,接收“当前”数字,并在单独的变量中计算其中的数字6,5和4,将找到该数字的所有可能结尾并计算它们的总和。像这样的东西(伪代码):
func rec(current, n4, n5, n6) // we have used n4 4's, n5 5's and n6 6's
// and formed the number current
// Let's account for it and add some more digits
if (n4>1)||(n5>2)||(n6>3) return 0 // no numbers satisfy the conditions
// print "Started ", current, n4, n5, n6 // if you want to debug
ans = current // account for current number
ans += rec(current*10+4, n4+1, n5, n6) // append 4
ans += rec(current*10+5, n4, n5+1, n6) // append 5
ans += rec(current*10+6, n4, n5, n6+1) // append 6
// print "Finished ", current, "answer=", ans // if you want to debug
return ans
...
answer = rec(0, 0, 0, 0)
这种方法在概念和编码方面都非常简单,并且可以非常容易地适应任何新的要求。
答案 2 :(得分:1)
一种“有趣”的方法:
l = [{0: [4, 5, 5, 6, 6, 6]}]
此处l
将包含n
个数字的所有数字,即l[0]
包含带有“0”数字的数字(哲学类型......),l[1]
一个数字,等等l[n]
实际上是一个字典,其中键是数字本身,值是可用数字列表继续算法(但算法是什么?!)。
def run (l, n = None):
if n is None:
n = len(l[0][0])
if n == 0:
return l
d = {}
for k, r in l[-1].items(): # Retrieve the last column of l (the largest number)
# k is the number, r the remaining values
for i, v in enumerate(r):
d[10 * k + v] = r[:i] + r[i+1:]
l.append(d)
return run (l, n - 1)
然后结果是l:
中所有dict的所有键的总和l = run([{0: [4, 5, 5, 6, 6, 6]}])
r = sum(map(lambda d: sum(d.keys()), l))
这是评论部分讨论的答案:
def mySum (x, y, z):
l = [{0: x * [4] + y * [5] + z * [6]}]
l = run(l)
return sum(map(lambda d: sum(d.keys()), l))
然后你只需:
x, y, z = raw_input().split()
print(mySum(int(x), int(y), int(z)))
答案 3 :(得分:0)
您可以使用排列预先生成数字。我为生成所有排列做了一个小例子,但是在中间循环或最后一个循环中,你可以计算4个,5个和6个的数字。或者为此创建一个单独的方法,但它会让你知道如何解决这个问题。通过使用哈希集,您将获得唯一的数字。
为了便于阅读,我建议您将其重写为带有计数器数字的递归方法。
var numbers = " 456"; HashSet perm = new HashSet(); foreach(char n1 in numbers) { string val1 = Char.ToString(n1); if(val1.Substring(0,val1.Length).Contains(" ")) continue; foreach(char n2 in numbers) { string val2 = val1; if(!val1.Substring(0,val1.Length-1).Contains(' ')) val2 += n2; foreach(char n3 in numbers) { string val3 = val2; if(!val2.Substring(0,val2.Length).Contains(" ")) val3 += n3; perm.Add(Int32.Parse(val3)); } } }