CSDN首页 空间 新闻 论坛 Blog 下载 读书 网摘 搜索 .NET Java 视频 接项目 求职 在线学习 买书 程序员 通知
不看会后悔的Windows XP之经验谈 简单快捷DIY实用家庭影院
CSDN社区
搜索 收藏 打印 关闭
CSDN社区 >  Java >  J2SE / 基础类

急求一个算法,请高手指点

楼主haroldzhh(haroldzhh)2003-12-02 17:38:19 在 Java / J2SE / 基础类 提问

已知:一百个不连续的数(有小数也有整数),并知道一个结果A  
   
  我希望从这一百个数里找出四个数相加等于上面那个已知的结果A,请高手给出  
  实现的逻辑或代码,谢谢各位!!!!!!!! 问题点数:0、回复次数:18Top

1 楼mq612(五斗米)回复于 2003-12-02 17:44:40 得分 0

用4个for把所有可能性都试一遍。  
  Top

2 楼xiaohaiz(城里的老土,两眼依然通红!)回复于 2003-12-02 17:51:37 得分 0

命题不严格嘛。是要一个结果?还是所有可能的结果?  
  重复算不算?比如A=100,队列中有一个25,捡出来4次相加也得100,算不算?  
  分析无法做,哪里来得试验。Top

3 楼ddbean(Welsh)回复于 2003-12-02 17:54:26 得分 0

不如楼主把题目改一改Top

4 楼haroldzhh(haroldzhh)回复于 2003-12-03 13:54:52 得分 0

xiaohaiz(老土进城,两眼通红):  
   
   
   
        我想要不重复的结果,一个就可以了Top

5 楼crazyman700(crazyman700)回复于 2003-12-03 14:25:01 得分 0

题目不严谨Top

6 楼79cy(火焰)回复于 2003-12-03 14:58:51 得分 0

这些数如果是大小有序的,可以采用分类的方法,  
  比如A=100,队列中如下:1,2,...37,89,98,99等,将1,2,等较小的(既i*4也<100)分为一类,将98,99等较大的分为另一类(既i*4也>>100),可以跳过选取89,98,99,87这样的组合,能减少部分工作量,至于如何分组看楼主的意思了,这个分组法还不是很成熟。Top

7 楼79cy(火焰)回复于 2003-12-03 15:20:35 得分 0

再补充几句:  
        这个方法的主要是可以排除一些明显不符合条件的组合,比如4个数相加太小或是太大的数组合。比如,我们取了1这个类中的3个数,将直接去99这个类中取,而不用再在1这个类里去实验,因为肯定不合适。Top

8 楼qm0445(海狗)回复于 2003-12-03 15:24:40 得分 0

HOHO!帮UP:)Top

9 楼xiaohaiz(城里的老土,两眼依然通红!)回复于 2003-12-03 17:13:50 得分 0

俺暂时没有想到有什么更好的算法来处理,但是正常的想法就是4次遍历。可以就此方法展开一下。1楼的兄弟“mq612(理想)”提出的做法是一个很自然的做法,“用4个for把所有可能性都试一遍。”俺们可以肯定这一定是可行的。类似这样:  
  <<  
  for(   ...   )  
      for   (   ...   )  
          for   (   ...   )  
              for   (   ...   )  
  >>  
  但是楼主的条件是又不允许重复,所以还需要加上很多判断的临时标示变量。另外,如果变化数目,修改量也是很大,语句就变得很复杂。所以,俺们可以看看有没有更好的办法来做这些遍历。  
  换一个思路这么看,这一系列数据(100个),可以看作一个聚集来处理。需要做的就是使用迭代来遍历所有的数据,而且可能需要多次迭代(需要2个数就迭代2次,需要3个数就迭代3次,类推),这样,无论需要多少个数,只要多次迭代嵌套就可以了。问题在于,如何在一次迭代的时候避免其他的迭代当前正在处理的INDEX(避免重复)。于是,俺们可以考虑增加一个迭代的缓存来实现这点重复的剔除。俺做了这么一个聚集的简单实现如下:  
  <<  
  final   class   NumberCollections   {  
          private   final   Map   iteratorBuffer   =   new   HashMap();  
          private   final   BigDecimal[]   nums;  
   
          public   NumberCollections(BigDecimal[]   nums)   {  
                  if(nums==null)   throw   new   NullPointerException();  
                  this.nums   =   new   BigDecimal[nums.length];  
                  System.arraycopy(nums,   0,   this.nums,   0,   nums.length);  
          }  
   
          public   Iterator   iterator()   {  
                  Iterator   it   =   new   DefaultIterator();  
                  iteratorBuffer.put(it,   new   Integer(0));  
                  return   it;  
          }  
   
          //   private   :  
          private   boolean   isIndexInBuffer(Iterator   thisIt,   int   index)   {  
                  for(Iterator   it=iteratorBuffer.keySet().iterator();it.hasNext();)   {  
                          Iterator   each   =   (Iterator)it.next();  
                          if(each==thisIt)   continue;  
                          Integer   eachIndex   =   (Integer)iteratorBuffer.get(each);  
                          if(eachIndex.intValue()==index)   return   true;  
                  }  
                  return   false;  
          }  
          private   void   updateBuffer(Iterator   it,   int   currentIndex)   {  
                  if(!iteratorBuffer.containsKey(it))   return;  
                  iteratorBuffer.put(it,   new   Integer(currentIndex));  
          }  
          private   void   removeBuffer(Iterator   it)   {  
                  iteratorBuffer.remove(it);  
          }  
   
          private   class   DefaultIterator   implements   Iterator   {  
                  private   int   index   =   0;  
                  public   boolean   hasNext()   {  
                          if(index==nums.length)   {  
                                  removeBuffer(this);  
                                  return   false;  
                          }  
                          for(int   i=index;i<nums.length;i++)   {  
                                  if(!isIndexInBuffer(this,   i))   return   true;  
                          }  
                          removeBuffer(this);  
                          return   false;  
                  }  
   
                  public   Object   next()   {  
                          for(int   i=index;i<nums.length;i++)   {  
                                  if(!isIndexInBuffer(this,   i))   {  
                                          updateBuffer(this,   i);  
                                          index   =   i+1;  
                                          return   nums[i];  
                                  }  
                          }  
                          return   null;  
                  }  
   
                  public   void   remove()   {  
                          throw   new   UnsupportedOperationException();  
                  }  
          }  
  }  
  >>  
  由于楼主的数据允许整型和浮点,所以使用BigDecimal来处理之。关键在于DefaultIterator这个迭代的实现类和iteratorBuffer的交互处。程序写的比较仓促。:)  
  在这样的聚集的前提之前,客户端就可以不用处理迭代的逻辑了,只需要简单的嵌套进行迭代即可(应该还有更好的方式来处理)。  
  简单的例子如下:  
  <<  
                  NumberCollections   nc   =   new   NumberCollections(nums);  
                  for(Iterator   it1=nc.iterator();   it1.hasNext();   )   {  
                          BigDecimal   n1   =   (BigDecimal)it1.next();  
                          for(Iterator   it2=nc.iterator();   it2.hasNext();   )   {  
                                  BigDecimal   n2   =   (BigDecimal)it2.next();  
                                  for(Iterator   it3=nc.iterator();   it3.hasNext();   )   {  
                                          BigDecimal   n3   =   (BigDecimal)it3.next();  
                                          for(Iterator   it4=nc.iterator();   it4.hasNext();   )   {  
                                                  BigDecimal   n4   =   (BigDecimal)it4.next();  
   
                                                  if(validate(n1,n2,n3,n4))   {...}  
                                          }  
                                  }  
                          }  
                  }  
  >>  
  只需要实现validate方法来验证是否是需要的组合就可以了。  
  BTW,如果数据量很大,这样的算法一定效率非常低下,并不推荐采用。Top

10 楼silverswords(笨笨虫冲)回复于 2003-12-03 17:36:13 得分 0

分组的方法应该是能减少运算量的  
  首先对100个数字进行排序  
  然后分4组  
  初步设定个组的边界值为   0,25,75,100  
  (如果100个数里有这几个值正好,没有也无所谓,最后去掉包含这4个数的组合就是)  
   
  这样,我们可以得到4组数据  
  0~25,26~50,51~75,76~100  
  A                 B               C                 D      
  下面可以通过简单的分析得到一些规律  
  2A+2B=100  
  2A+C=100  
  A+C=100  
  2A+D=100  
  (也许还有,数字的意思是从该区域取多少个)  
  由于我们要求是4个数字相加,且不重复  
   
  这样,可能的取法  
  2A+2B  
  (呵呵,好像就这么一种吧)  
   
  嗯,思路是这样的,算是抛砖引玉吧  
  ^_^Top

11 楼silverswords(笨笨虫冲)回复于 2003-12-03 17:37:39 得分 0

嗯,还有  
  3A+C  
  3A+D  
  这下应该没有了  
  Top

12 楼silverswords(笨笨虫冲)回复于 2003-12-03 17:40:07 得分 0

还有  
  3A+B  
  也有可能等于100  
   
  呵呵  
  其实这些可能的组合  
  也可以通过程序推出来的  
  有兴趣自己推吧  
  Top

13 楼binbin2000(binbin)回复于 2003-12-03 17:40:59 得分 0

三步走  
  一,排序  
  二,找到比A大的位置  
  三,选择,从找到的位置往小的方向选择4个数,如果和为A。ok。最后找完为止。Top

14 楼stonecsdn(东东)回复于 2003-12-03 18:04:41 得分 0

如果不允许重复,用四个for   也是可以的(前提不考虑数据结构和时间复杂度):  
  假设数据存放在Array中,  
  for(int   i=0;i<Array.length;++i){  
      for(int   j=0;j<Array.length;++j){  
              if(i==j)   break;  
              for(int   k=0;k<Array.length;++k){  
                      if((k==i)||(k==j))   break;  
                      for(int   n=0;l<Array.length;++l){  
                                    if((n==i)||(n==j)||(n==k))   break;  
                                          if((Array[i]+Array[j]+Array[k]+Array[n])==result)  
                                                              ....相关处理  
                        }  
                }  
        }  
  }  
   
  如果要提高效率,最好先进行排序,向楼上几位提的。防止计算向四个大于50的数的相加。Top

15 楼xiaohaiz(城里的老土,两眼依然通红!)回复于 2003-12-03 18:18:04 得分 0

谢谢silverswords(笨笨虫冲),提出的分组算法确实能够很大程度减少运算量,比4次遍历强太多了。不过那样的分组算法还不够完善,俺来补充一下:  
   
  首先,对整个数列进行排序,俺们可以想象这些数分布在一条数轴之上。  
  然后,俺们可以剔除无解的情况?两种无解:  
  (1)   最小的连续4个数相加大于A无解;  
  (2)   最大的连续4个数相加小于A无解;  
   
  接下来,俺们可以把A线段提出来,A线段多大?从最小数点到A点的距离即为A线段的长度。  
  然后,把A线段平均切分为4段,记为S1,   S2,   S3和S4。然后把数轴上所有数列中的数放入到相应的4段中(在这一步就可能可以剔除很多无用的数据了)  
  下面要做的事情,就是按照“silverswords(笨笨虫冲)”推出的公式进行遍历计算,得到所有可能得到A的值,比如   3S1   +   S3   =   A;   3S1   +   S4   =   A;   2S1   +   2S2   =   A。  
   
  如果算法修改成这样,确实效率会得到很大的改善。  
  Top

16 楼stonecsdn(东东)回复于 2003-12-03 21:55:25 得分 0

不好意思,上面的break应换为continue;Top

17 楼79cy(火焰)回复于 2003-12-04 09:55:03 得分 0

昨天又想了一下,我认为分组应该以分数为为界线,以100为例,因为取四个数,所以分4段,分界点分别为100/2,100/3,100/4,这样可以在四重嵌套循环中,分取这四类数据,比如上述数据分别为A类(<25),B类(>25&&<33),C类(>33&&<50),D类(>50&&100),这样在取了3个A类数据后,可以直接去取D类数据,而不用考虑B类,C类。  
  取数的思路是:首先4个数中必有A类,其次D类的数最多1个,C类的数最多2个,B类的数最多3个,而A类的数最多为3个,而取数与顺序无关。  
  所以可以规定第一个数必须为A类,第二个数可以任选A,B,C,D类,第三个数可以根据思路排除一些不可能的选取法,第四种一般可以根据前3个数的类型唯一确定它的类型。Top

18 楼fantasyCoder(Attitude is everything)回复于 2003-12-04 10:45:54 得分 0

用回朔!!!Top

相关问题

  • 求解算法,敬请各位指点
  • 求一算法,请高人指点
  • 算法问题,请高手指点,很急,在线等候,马上给分!
  • 帐户密码专列:征求ASP可逆算法代码?急!!请高手指点江山,激扬代码.
  • 帐户密码专列:征求可逆算法代码?急!!请VC高手指点江山,激扬代码.
  • 帐户密码专列:征求可逆算法代码?急!!请DELPHI高手指点江山,激扬代码.
  • 请教一个sql的算法,请高手指点
  • 急,请指点!
  • 请行家指点: 关于图形处理算法
  • 图象缩小算法:请高手指点!

关键词

  • 算法
  • 组合
  • 数据
  • 数字
  • 迭代
  • 个数
  • 遍历
  • 相加
  • 处理
  • 需要

得分解答快速导航

  • 帖主:haroldzhh

相关链接

  • CSDN Java频道
  • Java类图书
  • Java类源码下载

广告也精彩

反馈

请通过下述方式给我们反馈
反馈
提问
网站简介|广告服务|VIP资费标准|银行汇款帐号|网站地图|帮助|联系方式|诚聘英才|English|问题报告
世纪乐知(北京)网络技术有限公司 版权所有, 京 ICP 证 020026 号
北京创新乐知广告有限公司 提供技术支持
Copyright © 2000-2007, CSDN.NET, All Rights Reserved
GongshangLogo