[英]c programming puzzle
给定一个数组,其所有元素都是正数,找到一个子序列的最大总和,其约束条件是序列中没有2个数字应该在数组中相邻。 所以3 2 7 10应该返回13(3和10的总和)或3 2 5 10 7应该返回15(3,5和7的总和)。
我尝试使用所有可能允许的总和,然后找到最大值(蛮力方法)但是有更好的方法。 例如[3 2 7 10]我总和3,7和2,10并取最大值。
更多例子:
这个问题可以通过动态编程来解决。
假设我们有一个整数数组:
i[1], i[2], i[3], ..., i[n], i[n+1], i[n+2]
我们将数组分为两部分:第一部分包含前n个整数,第二部分是最后两个整数:
{i[1], i[2], i[3], ..., i[n]}, {i[n+1], i[n+2]}
我们将M_SUM(n)
表示为每个要求的前n个整数的最大和。
将有两种情况:
i[n]
不计入M_SUM(n)
,那么M_SUM(n+2) = M_SUM(n) + MAX(i[n+1], i[n+2])
i[n]
被计入M_SUM(n)
,那么M_SUM(n+2) = M_SUM(n) + i[n+2]
那么,我们正在寻找的值M_SUM(n+2)
将是上述两个值中较大的值。
然后我们可以有一个非常天真的伪代码如下:
function M_SUM(n)
return MAX(M_SUM(n, true), M_SUM(n, false))
function M_SUM(n, flag)
if n == 0 then return 0
else if n == 1
return flag ? i[0] : 0
} else {
if flag then
return MAX(
M_SUM(n-2, true) + i[n-1],
M_SUM(n-2, false) + MAX(i[n-1],i[n-2]))
else
return MAX(M_SUM(n-2, false) + i[n-2], M_SUM(n-2, true))
}
“flag”表示“允许使用最后一个整数”
该算法具有指数时间复杂度。
可以采用动态编程技术来消除M_SUM的不必要的重新计算。
将每个M_SUM(n, flag)
存储到* 2矩阵中。 在递归部分中,如果矩阵中不存在这样的值,则计算它。 否则,只需从矩阵中获取值。 这会将时间复杂度降低为线性。
该算法将具有O(n)时间复杂度和O(n)空间复杂度。
Python,六行使用动态编程( 不是真的!见下面的编辑。 ):
def run(x):
if len(x) == 0:
return 0
elif len(x) <= 2:
return max(x)
return max(x[0] + run(x[2:]), x[1] + run(x[3:]))
编辑和回滚:虽然上面的解决方案生成了正确的答案,但它不是动态编程。 下面是一个,它使用较少的函数调用:
def main(x):
return max(helper(x))
def helper(x):
if len(x) == 1:
return (0, x[0])
a, b = helper(x[:-1])
return (max(a, b), x[-1] + a)
以[3,2,5,10,7]为例
解决方案使用动态编程
维护两个数组,如最后两行所示
alt text http://img44.imageshack.us/img44/4843/newgp.jpg
答案将是最后一列中最多两个值(红色粗体)
F#解决方案:
let rec maxsubset = function
| [] -> 0
| x::[] -> x
| x::y::xs -> max (maxsubset (y::xs)) (x + maxsubset xs)
轻松适应类C语言:
using System;
using System.Linq;
namespace Juliet
{
class Program
{
static int MaxSubset(int[] arr, int offset)
{
if (offset >= arr.Length)
return 0;
else
return Math.Max(MaxSubset(arr, offset + 1), arr[offset] + MaxSubset(arr, offset + 2));
}
static void Test(params int[] nums)
{
Console.WriteLine("----------------");
Console.WriteLine("MaxSubset({0}) = {1}", String.Join(", ", nums), MaxSubset(nums, 0));
}
static void Main(string[] args)
{
Test(3, 2, 7, 1);
Test(6, 2, 1, 4);
Test(8, 9, 5, 1);
Test(29, 77, 16);
Test(29, 44, 16);
Test(239, 2, 3, 111, 1, 4, 546, 4, 3);
Test(100, 1, 1, 100);
Console.ReadLine();
}
}
}
package com.dan.alg.recursion;
/ ** *问题:给定一个正数组,找到一个子序列*的最大总和,其约束条件是序列中没有2个数字应该在数组中相邻。 *所以3 2 7 10应该返回13(3和10的总和)或3 2 5 10 7应该返回15 *(3,5和7的总和)。以最有效的方式回答问题。 *
*解决方案:我们将向后递归构建解决方案(从数组的最后一个位置*开始并按照我们的方式开始),基于以下观察:*
*位置p的最大总和可以从以下两个值的最大值中获得:* V1 =位置p的值+位置p-2的最大总和(记住,两个元素不能相邻)* V2 =位置的最大总和p - 1 * * @author dan * /
公共课MaxSumNoNeighbours {
private static int [] arr = { 29, 44, 16 };
/**
* Determine the max sum for the current position.
*
* @param currentPos the current position in the array.
*/
private static int maxSum(final int currentPos) {
// The sum is zero if we are outside of the bounds.
if (currentPos < 0) {
return 0;
}
return Math.max(
arr[currentPos] + maxSum(currentPos - 2),
maxSum(currentPos - 1));
}
public static void main (final String [] args) {
// Start from the end of the array and work your way forwards
System.out.println(maxSum(arr.length - 1));
}
}
sum[0] = 0;
sum[1] = 0;
for(i = 0; i < arraylength; i++)
sum[i & 1] += array[i];
printf("sum = %u\n", MAX(sum[0], sum[1]));
printf("homework completed\n");
可爱的问题。 最简单的方法似乎是迭代地考虑数组,保持两个最佳 - 最远的总和:允许使用[i]时可以得到的最佳总和,以及使用[i]时可以获得的最佳总和是允许的。 在python中:
def best(arr):
# best sums of zero length array are 0
ok, bad = 0,0
for x in arr:
# best sum if we can use x is to use it,
# because all elements are positive
ok += x
# moving along one step means we can't
# use the ok sum, and can use the bad sum
bad, ok = ok, bad
# but just because we could use ok, doesn't
# mean we have to, so if it's better, use
# that path
if bad < ok:
bad = ok
# bad is then our best possible sum
return bad
{
int a[10]={1,2,3,4,5,6,7,89,8,9};
int k=0,i,j,l;
int sum[36],max;
for (i=0;i<10;i++)
{
for (j=i+2;j<10;j++,k++)
sum[k]=a[i]+a[j];
}
max=a[0];
for(i=0;i<36;i++)
printf("sum[%d] is %d\n",i,sum[i]);
for(l=1;l<36;l++)
{
if(max>sum[l])
continue;
else
max=sum[l];
}
printf("%d is the max sum",max);
}
int findSum(int* arr, int sz)
{
if( sz <= 0) return 0;
if( sz == 1)
{
return arr[0];
}
else
{
int a = arr[0] + findSum(arr+2, sz-2);
int b = findSum(arr+1, sz-1);
if( a >= b)
return a;
else
return b;
}
}
考虑中间元素,它可能是解决方案的一部分。 对于每种情况,找到左右剩余子列表的最佳解决方案并将它们组合起来,然后选择两种情况中较好的一种。
int choose( int n)
{
if((n==1) || (n==0))
return array[n];
if( n==2)
return array[0];
totalSum += max(choose(n-2), choose(n-3));
}
max是一个从最大值中获取最大值的函数。
对于ARRAY“数组”,对数组的每个元素进行函数调用,并将最大结果存储在另一个数组中(比如arrayOfMax [n])
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.