Algorithm 如何求整数M的最大奇分解?
设M为[1;100000000]范围内的整数 M的分解是一组和等于M的唯一整数 如果分解只包含奇数整数,则分解为奇数 若并没有其他M的分解比集合的大小更大,则M的分解是最大的 编写一个函数:Algorithm 如何求整数M的最大奇分解?,algorithm,language-agnostic,Algorithm,Language Agnostic,设M为[1;100000000]范围内的整数 M的分解是一组和等于M的唯一整数 如果分解只包含奇数整数,则分解为奇数 若并没有其他M的分解比集合的大小更大,则M的分解是最大的 编写一个函数: int[] maxOddDecomposition(int M) 返回一个最大奇数分解为M的数组。数组中的数字应按升序排列。如果M没有任何奇数分解,则数组应为空。如果有多个正确答案,函数可能返回其中任何一个 例如,M=6有四种分解: 6 = 1 + 2 + 3 = 1 + 5 = 2 + 4
int[] maxOddDecomposition(int M)
返回一个最大奇数分解为M的数组。数组中的数字应按升序排列。如果M没有任何奇数分解,则数组应为空。如果有多个正确答案,函数可能返回其中任何一个
例如,M=6有四种分解:
6 = 1 + 2 + 3
= 1 + 5
= 2 + 4
= 6
只有1+5
是奇数分解,因此是最大奇数分解。我们应该以数组的形式返回它,使得数组[0]=1
和数组[1]=5
预期最坏情况下的时间和空间复杂度为O(sqrt(M))
我所尝试的: 由于时间复杂度必须是sqrt(M),这让我想起了M算法的朴素分解,我们从1迭代到sqrt(M)。不过,没有出现进一步的想法。只是它必须非常快,只有sqrt(M)步 所以,我做了一些例子。例如,如何找到20的答案?小于20的奇数是多少?1 + 3 + 5 + 7 + ... 我们已经有16个了。我们可以加4,但4是偶数 那么,让我们用(7+4)=11替换7,我们完成了:1+3+5+11。我注意到的是,最初的序列总是有floor(sqrt(M))元素,非常完美。让我们用伪代码对其进行编码:
int len = floor(sqrt(M));
int result[] = new int[len];
int sum = 0;
for (i = 0; i < len - 1; i++) {
result[i] = 1 + 2*i;
sum += result[i];
}
result[len - 1] = M - sum;
return result;
int len=楼层(平方米);
int result[]=新的int[len];
整数和=0;
对于(i=0;i
我对M=2做了一个特例,返回一个空数组。我以为就这样,菲尼托
我没有注意到它会被3打断,因为它给出的是1+2
,而不是3
。对于5,给出1+3+1
,而不是5
。还有更多
你将如何解决这个问题?这里有一个可行的想法。它需要从构造的贪婪集净删除最多1个 像往常一样构造O(sqrt(M))列表(没有
result[len-1]=M-sum;
)。如果总和不是平方数(即精确):
- 将下一个最大的奇数相加
- 取你现在的总数和你的目标数字->N之间的差额
- 如果N为奇数,请删除相应的数字
- 如果N是偶数而不是2,则删除小于N的最大奇数,并删除1
- 如果N为2,则删除刚才添加的倒数第二个数字。这将产生差异0
- 如果按顺序添加连续奇数,则列表应尽可能密集-即,不能有更大的列表
- 此外,差异始终以您在步骤2中添加的奇数为界,因此最多两个数字的净删除始终是奇数或偶数差异的原因李>
- 假设您想要42:construct[1,3,5,7,9,11],add 13=>sum=49,remove 7(无净删除)
- 您需要39:构造[1,3,5,7,9,11],添加13,删除1和9(净删除1)
- 您需要38:构造[1,3,5,7,9,11],添加13,删除11(无净删除)
编辑:最后一个案例中的错误由@user1952500纠正,这里是问题的确定性解决方案。假设M={1,3,5,…,2*k-3,2*k-1,r},其中r3(前面案例的推理和处理将在后面介绍): 案例1。如果r是奇数且等于2*k+1:将r添加到列表中,从而给出(k+1)元素的分解 案例2。如果r是偶数:将{(2*k-1),r}替换为{2*k-1+r},给出k元素的分解 案例3。如果r是奇数且不等于2*k+1:将序列{1,2*k-1,r}中的第一个和最后两个元素替换为{2*k+r},给出(k-1)元素的分解 请注意,当输入的形式为n^2+(奇数<2*k+1)时,将出现(k-1)元素的最坏情况 还要注意,如果元素数少于3,则(情况3)将中断。例如,分解5和7。我们将不得不对这些数字进行特殊处理。同样(案例2)将中断3次,并且必须进行特殊处理。对于M=2,没有解。因此,上述限制k>3。其他一切都应该很好 这需要
O(sqrt(M))
步骤
一些C/C++代码:
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("Enter M:");
int m = 0;
scanf("%d", &m);
int arr[100] = {0};
printf("The array is:\n");
switch(m) {
case 2:
printf("No solution\n");
return 0;
case 1:
case 3:
case 5:
case 7:
printf("%d\n", m);
return 0;
}
int sum = 0;
int count = 0;
for (int i = 1; (sum + i) < m; i+= 2) {
arr[count++] = i;
sum += i;
}
int start = 0;
int r = m - sum;
if (r % 2 == 0) {
arr[count - 1] += r;
} else if (r > arr[count - 1]) {
arr[count++] = r;
} else {
start = 1;
arr[count - 1] += r + 1;
}
for (int i = start; i < count; i++) {
printf("%d\n", arr[i]);
}
return 0;
}
我不明白人们为什么要把事情弄得这么复杂。奇数分解就像一个侧面翻转并展开的分区,例如,
n=13
4 4 3 2 => => => 7 5 1
x x x x rotate x unfold out x x x x x x x
x x x x clockwise ↖ x x ↗ each side x x x x x
x x x 45 degrees x x x => x
x x x x x x
x x x
奇分解越大,相应自共轭的“边界平方”越大。所谓“边界正方形”,我指的是左上角的正方形,它在所有大小相似的奇数分解中都是常数。例如,我们可以将13
写成自共轭{5,3,3,1,1}
,9单元的“边界平方”将保持不变,并进行相应的奇数分解{9,3,1}
:
5 3 3 1 1 => 9 3 1
x x x x x x x x x x x x x x
x x x x x x
x x x x
x
x
要得到具有最大基数的奇数分解,请找到具有偶数余数的最大“边界平方”
例如:
Enter M:24
The array is:
1
3
5
15
Enter M:23
The array is:
3
5
15
M = 24
Bounding square | remainder
1 23
4 20
9 15
16 8
25...too large
Place the remainder in any diagonally-symmetric way you like. The simplest way might be
xxxx xxxxxxxx
xxxx => xxxx
xxxx xxxx
xxxx xxxx
x
x
x
x
Decompose: 15,5,3,1
我认为这个Haskell代码输出了所有的可能性:
fm=g[1,3..bestRoot*2-1]余数0[]
式中,根=地板(平方米)
bestRoot=head$dropWhile(\x->odd(m-x^2))[root,root-1..1]
余数=m-最佳根^2
g(x:xs)r上一个res
|null xs=[反向((x+r):res)]
|否则=do r'闻起来像codechef&co。不确定这样一个问题的位置。Sqrt(n)很可能来自于1+3+5+7+。。“总和是二次增长的。”AdamStelmaszczyk笑着说。也许你应该试试某种形式的回报
*Main> f 24
[[1,3,5,15],[1,3,7,13],[1,5,7,11],[3,5,7,9]]
*Main> f 23
[[1,3,19],[1,5,17],[1,7,15],[3,5,15],[3,7,13],[5,7,11]]
*Main> f 38
[[1,3,5,7,9,13]]
*Main> f 37
[[1,3,5,7,21],[1,3,5,9,19],[1,3,7,9,17],[1,5,7,9,15],[3,5,7,9,13]]
*Main> f 100
[[1,3,5,7,9,11,13,15,17,19]]