算法题3:携程实习生笔试:求一个整数的加数的最大乘积(允许加数相同和不同)

版权声明:转载请联系作者 https://blog.csdn.net/sinat_21591675/article/details/83244694

给出一个整数n,将n分解成至少两个整数之和,使得这些整数的乘积最大化,输出能获得的最大的乘积。

(1) 允许存在相同的加数

(2) 不允许存在相同的加数

1. 允许存在相同的因子

给出一个整数n,将n分解成至少两个整数之和,使得这些整数的乘积最大化,输出能获得的最大的乘积。
输入描述 : 输入为一个整数
输出描述 :输出为一个整数
样例
in: 10
out: 36
(10=5+5=2+3+2+3, 36=232*3)

思路:

给你一个数n = a + b,a * b何时最大?
学过基本不等式的都知道, a b < = ( a + b ) / 2 a*b<=(a+b)/2 ,当 a = b a=b 时取等号。因此,当 a 和 b 尽量靠近时,乘积 a b a*b 才最大。
那如果n可以分解成多个数字相加,那么这些数字相乘什么时候最大?
答案很明显,当然是因子尽可能相近时,乘积才最大。
所谓相近,就是任意两个数之差的绝对值小于等于1,那么这些数字必然可以分解成x, x, x, …,x + 1, x + 1, …这种形式。

Q:为什么乘积存在极大值?
A:把一个正整数N拆成若干正整数只有有限种拆法,所以存在最大乘积。
推广:如果情况的种类数有限,那么一定存在极值;但是如果无限,也可能存在极值。

在 知乎 https://www.zhihu.com/question/30071017/answer/47584748 中,作者给出了一种清奇的做法,让我醍醐灌顶。摘录要点如下[资料3]:

把一个正整数N拆成若干正整数只有有限种拆法,所以存在最大乘积。 假设 N = n 1 + + n k N=n_1+…+n_k ,并且 n 1 × × n k n_1×…×n_k 是最大乘积。

结论:

  1. 乘积中不存在1或者超过(包含)5的整数。
  2. 选用尽量多的3,直到剩下2或者4时用2。

证明:

  1. 显然1不会出现在其中;

  2. 如果存在 n k 5 n_k≥5 ,则我们将 n k n_k 改为 3 + n k 3 3+n_k−3 。而 3 × ( n k 3 ) = 3 n k 9 > n k 1 3×(n_k−3)=3n_k−9>n_k*1 。所以不存在大于等于5的因子;

  3. 4 = 2 + 2 4=2+2 ,乘积不变,不妨设没有因子4;

  4. 如果有三个以上的2, 那么 3 × 3 > 2 × 2 × 23 × 3 > 2 × 2 × 2 3×3>2×2×23×3>2×2×2 ,所以替换成3乘积更大

对于2.证明,可能一开始看不懂,这里详细再说一下:
因为 n k 5 n_k≥5 ,所以 2 n k 10 2n_k≥10 ,所以 ( 3 n k 9 ) n k = 2 n k 9 10 9 = 1 > 0 (3n_k-9)-n_k=2n_k-9≥10-9=1>0 ,所以 3 n k 9 n k 3n_k−9≥n_k

根据这种清奇的思路:最大乘积的分解式中,只可能存在3和2两者元素;尽可能取3,剩下的再取2

编码如下:

# coding:utf-8
# Python 3.6

import sys
# import numpy as np
# 这里用自己编写的 power 函数,当然也可以用numpy.power。
def power(a, b):
	if type(b)==int: 
		n = 1
		for i in range(b):
			n*=a

	return n


if __name__=='__main__':
	data = sys.stdin.readline().strip()
	number = int(data)
	max_product = 0
	p = 0
	q = 0

	if number <=3:
		max_product = number
	else:
		res = number % 3
		if res==0:  # 如果正好能整除
			p = number / 3
		if res==1: # 如果余1,那3+1要拆分成2+2
			p = number // 3 - 1
			q = 2
		if res==2:  # 如果余2,那么就直接用2
			p = number // 3
			q = 1
		# max_product = np.power(3, p) * np.power(2, q)
		max_product = power(3, p) * power(2, q)
		max_product = int(max_product)

	print('Max product is ', max_product)

2. 不允许存在相同的加数

给出一个整数n(n>=5),将n分解成至少两个整数之和,使得这些整数的乘积最大化,输出能获得的最大的乘积。
输入描述 : 输入为一个整数
输出描述 :输出为一个整数
样例
in: 10
out: 30
(10=2+3+5, 30=235)

思路:这种题目没有巧妙的解法,只能手写前面几种基本情况,找找规律。例如:
#3=1+2
#4=1+3
5=2+3
6=2+4
7=3+4
8=3+5
9=2+3+4
10=2+3+5
11=2+4+5
12=3+4+5
13=3+4+6

由此可见:
(1)加数从2开始逐渐递增,2, 3, 4, … 尽量使得元素是连续的。连续意味着靠近,因此乘积会比较大。这一点与第一种情况是相似的。
(2)当按照2, 3, 4, …展开,如果剩余数值还大于0的话,那么就将其从后往前均匀分配到各个元素。
注意:考虑到一种特殊情况,当多出来的数比前面已有元素的个数大1时(比如8=3+4+1的情况),先给已有元素的最大元素加1(8=3+5),然后再均匀分配到每个元素。

编码如下:

# coding: utf-8
# Python 3.6


import sys
# import numpy as np

def power(a, b):
	if type(b)==int: 
		n = 1
		for i in range(b):
			n*=a

	return n


if __name__=='__main__':
	data = sys.stdin.readline().strip()
	number = int(data)
	max_product = 1

	flag = []
	k = 2

	if number<2:
		print('Wrong! Input number must be larger than 1!')
	else:
		while(number >=k):
			flag.append(k)
			number -= k
			k += 1

		#  说明有剩余的
		if number > 0:
			# 说明这时候剩余的数正好比已有的元素个数多1,所以要先给最后一个元素加1
			if number - 1 == len(flag):
				flag[-1] += 1
				number -= 1


			for i in range(number):
				flag[-1 - i] += 1

		# 分解完以后,就求乘积
		for x in flag:
			max_product *= x
			
		print('Max product is %s'%max_product + ' = ', end='')

		for x in flag:
			print(str(x) + '*', end='')

		print('\b')

【参考资料】

[1] 正整数分解使得乘积最大问题
[2] 招商银行信用卡2018春季招聘研发(第一批)编程题 - 题解
[3]【整理自用】清奇思路(三)正解整数分解成不同加数的最大乘积
[4] 知乎:有一个正整数N可以分解成若干个正整数之和,问如何分解能使这些数的乘积最大?求详细解释。

猜你喜欢

转载自blog.csdn.net/sinat_21591675/article/details/83244694