免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 4217 | 回复: 13
打印 上一主题 下一主题

[算法] 请教一个求数组部分和的是否等于某数的算法 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-02-14 19:27 |只看该作者 |倒序浏览
假如有一个数组A,数组元素个数为SIZEA,现在给你一个整数M,求一个最小整数k,使得k个数组元素之和等于M,注意这里要保证k最小,如果不存在这样的k返回-1。

论坛徽章:
0
2 [报告]
发表于 2006-02-14 20:50 |只看该作者
  将数组A排序,设为升序.

  接下来好办了吧,遍历相加,如果相等或大于就跳出就好了

论坛徽章:
0
3 [报告]
发表于 2006-02-14 20:53 |只看该作者
用hash表,
扫描一遍数组
到Ai时,计算到此位置时的部分和Si,
在hash表里查询Si-M
然后把(Si,i)插入hash表
扫描完找到最小k就结束了

hash表里对于Si相同的节点,保存更新的位置

O(n)的复杂度和空间复杂度

[ 本帖最后由 ArXoR 于 2006-2-14 20:57 编辑 ]

论坛徽章:
0
4 [报告]
发表于 2006-02-14 22:04 |只看该作者
2楼的算法不对,遍历相加的情况是不全面的,也可能排序后的结果是A[1]和某个A[i]加和刚好是M
3楼的算法我没看懂

论坛徽章:
0
5 [报告]
发表于 2006-02-14 22:14 |只看该作者
就是对于每个Ai我们都希望判定它是不是一个和为M的子串的尾部
而如果知道到Ai为止的部分和Si,那就是看之前是否存在Sj=Si-M,这个用hash最好
而我们总是希望找最大的j,这样我们只要记录有序对(Sx,y),y是当前得到的Sx的最后的位置
应该就是这样了吧

论坛徽章:
0
6 [报告]
发表于 2006-02-15 11:19 |只看该作者
对于序列A1,A2,A3...以及一个预设的和M,对于某个值An,假设:
S=A_i+...+A_n-1 <= M(若i不存在,则认为i=n, S=0)
则令S=S+A_n,其值有三种可能:
(1)S<M,则继续下一个值,累加入S
(2)S>M,则减去A_i, A_i+1...直至S<=M为止
(3)S=M,则得到一个连续和为M的子列,与到目前为止,最短的连续串(长度设为min_k)相比,以得到的min_k
最后就得到了和为M的最短连续子列
  1. int sub_sum(int *array, int n, int m, int *start)
  2. {
  3.     int s=0, min_k=n+1, i, begin=0;
  4.     for(i=0; i<n; i++) {
  5.         s += array[i];
  6.         while(s > m)  s -= array[begin++];
  7.         if(s == m && i-begin+1 < min_k) {
  8.             min_k = i-begin+1;
  9.             *start = begin;
  10.         }
  11.     }
  12.     return min_k;
  13. }
复制代码

[ 本帖最后由 yzc2002 于 2006-2-15 11:23 编辑 ]

论坛徽章:
0
7 [报告]
发表于 2006-02-15 11:39 |只看该作者
sorry!没看清.
如果可以是不连续的话,则用动态规划
S(n,M)=min(S(n-1, M-An)+1, S(n-1, M))

论坛徽章:
0
8 [报告]
发表于 2006-02-15 14:07 |只看该作者
原帖由 yzc2002 于 2/15/06 11:19 发表
对于序列A1,A2,A3...以及一个预设的和M,对于某个值An,假设:
S=A_i+...+A_n-1 <= M(若i不存在,则认为i=n, S=0)
则令S=S+A_n,其值有三种可能:
(1)S<M,则继续下一个值,累加入S
(2)S>M,则减去A_i, A_i+1 ...


如果我没理解错,要求全是非负数才能这样做吧?

论坛徽章:
0
9 [报告]
发表于 2006-02-15 14:50 |只看该作者
原帖由 fsilence 于 2006-2-14 19:27 发表
假如有一个数组A,数组元素个数为SIZEA,现在给你一个整数M,求一个最小整数k,使得k个数组元素之和等于M,注意这里要保证k最小,如果不存在这样的k返回-1。


1。先对a从大到小排序。
2。

  1. int num = M;

  2. int checkM()
  3. {
  4. int count = 0;
  5. (for i=0; i<sizea; i++)
  6. {
  7.    num -= A[i];
  8.    if(num > 0)
  9.    {
  10.       count++;
  11.    }
  12.    else if(num == 0)
  13.   {
  14.       count++;
  15.       break;
  16.    }
  17.     else
  18.     {
  19.        return -1;
  20.     }
  21. }

  22. return count;
  23. }

复制代码

论坛徽章:
0
10 [报告]
发表于 2006-02-15 14:53 |只看该作者
原帖由 ArXoR 于 2006-2-14 20:53 发表
用hash表,
扫描一遍数组
到Ai时,计算到此位置时的部分和Si,
在hash表里查询Si-M
然后把(Si,i)插入hash表
扫描完找到最小k就结束了

hash表里对于Si相同的节点,保存更新的位置

O(n)的复杂度和空间复杂度


这种方法求出来的总是连续和,是吗? 或者我理解错了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP