博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
数组面试题-子数组之和
阅读量:5985 次
发布时间:2019-06-20

本文共 2057 字,大约阅读时间需要 6 分钟。

昨天在一位老兄的凡客面试题中看到的,拿来写一下。

题目描述

给定一个含有n个元素的整形数组a,再给定一个和sum,求出数组中满足给定和的所有元素组合,举个例子,设有数组a[6] = { 1, 2, 3, 4, 5, 6 },sum = 10,则满足和为10的所有组合是

{1, 2, 3, 4}

{1, 3, 6}
{1, 4, 5}
{2, 3, 5}
{4, 6}

注意,这是个n选m的问题,并不是两两组合问题。

解法一:穷举法

最直观的想法就是穷举,把数组中元素的所有组合情况都找出来,然后看看哪些组合满足给定的和即可,这种方法的计算量非常大,是指数级的,假设数组有n个元素,那么所有组合的情况一共有2 ^ n种(包括空集),如果n很大的话,这个方法将会非常慢。那么如何找出所有这些组合呢?其实对于任意一个组合来讲,数组a中任意一个元素要么在这个组合中,要么不在这个组合中,我们用1表示在,用0表示不在,那么每一种组合实际上对应着一个01序列,而这个序列对应着一个十进制数,一共有多少种这样的序列呢?前面说了,是2 ^ n种,分别对应1 - 2 ^ n中的每一个十进制数,所以我们只需遍历这些数字,确定哪些位是1,将数组a中对应的数字放入组合中,再检查一下这个组合的和是否为sum即可。举个例子,在题目描述中我们说到a[6] = { 1, 2, 3, 4, 5, 6 },sum = 10,那么

{1, 2, 3, 4} 相当于 111100 (1, 2, 3, 4在组合中,而5, 6不在)

{1, 3, 6} 相当于101001

...

数组a有6个元素,所以我们要搜索64个数,只有上面的三种组合满足条件,其他的全部淘汰。

代码-输出函数

//
 输出一种组合,该组合取决于参数i
//
 将参数i写成二进制的形式,对于i中取值为1的位,取数组a中对应的元素放到组合中
//
 n是数组a中元素个数
// 在取a中元素的时候,方向是从后向前的,因为我们测试i中哪些位是1的时候是从右向左进行的。
void
 Output(
int
*
 a, 
int
 n, 
int
 i)
{
    
int
 k 
=
 n 
-
 
1
 ;
    
while
(i 
>
 
0
)
    {
        
if
(i 
&
 
1
)
            cout 
<<
 a[k] 
<<
 
"
"
;
        
--
k ;
        i 
>>=
 
1
 ;
    }
    cout 
<<
 endl ;
}

代码-主函数

void
 FixedSum(
int
*
 a, 
int
 n, 
int
 sum)
{
    
int
 total 
=
 (
1
 
<<
 n) ; 
//
组合总数
    
for
(
int
 i 
=
 
1
; i 
<
 total; 
++
i)
    {
        
int
 t 
=
 i ;
        
int
 s 
=
 
0
 ;
        
int
 k 
=
 n 
-
 
1
 ;
        
while
(t 
>
 
0
)
        {
            
if
(t 
&
 
1
)
                s 
+=
 a[k] ;
            
--
k ;
            t 
>>=
 
1
 ;
        }
        
if
(s 
==
 sum)
            Output(a, n, i) ;
    }
}

解法二:回溯法

很多数排列组合问题都可以用回溯法来解决,回溯相比上面方法的优点就是减少可行解搜索的范围,因为回溯一旦发现当前解不满足条件就会停止搜索,回溯并进入下一个分支进行搜索,比上面的方法快很多,这里使用的是回溯法中的子集树模型。对于数组中任意一个元素,先将其放入结果集中,如果当前和不超出给定和,那就继续考察下一个元素,如果超出给定和,则舍弃当前元素。如此往复,直到找到所有可行解。

首先定义一个标志位数组flag[],flag[i]如果为true,则表示a[i]在当前解中,如果flag[i]为false则表示不在。这个数组元素个数与数组a的元素个数相同。

bool
 flag[
100
=
 { 
false
 };

代码-输出函数

//
输出一种组合,该组合有n个元素
void
 Output(
int
*
 a, 
int
 n)
{
    
for
(
int
 i 
=
 
0
; i 
<
 n; 
++
i)
    {
        
if
(flag[i])
            cout 
<<
 a[i] 
<<
 
"
"
 ;
    }
    cout 
<<
 endl ;
}

代码-主函数

//
 a: 待搜索的数组
//
 n: 数组元素个数
//
 t: 已经存储的元素个数
//
 sum: 给定的和
void
 FixedSum(
int
*
 a, 
int
 n, 
int
 t, 
int
 sum)
{
   if(sum == 0)
        Output(a, t) ;
    
else
    {
        
if
(t
==
n
)
            return ;
        
else
        {
            flag[t] 
=
 
true
 ;
            
if
(sum 
-
 a[t] 
>=
 
0
)
                FixedSum(a, n, t 
+
 
1
, sum 
-
 a[t]) ;
            flag[t] 
=
 
false
 ;
            
if
(sum 
>=
 
0
)
                FixedSum(a, n, t 
+
 
1
, sum) ;
        }
    }
}

Happy Coding!!!

== THE END ==

转载地址:http://auylx.baihongyu.com/

你可能感兴趣的文章
多重保护成为云计算安全保障
查看>>
mssql系统存储过程
查看>>
手机影音第八天 控制视频播放页面的上面与下边的控制器布局的消失与隐藏...
查看>>
驱动过滤鼠标
查看>>
Centos7下配置phpMyAdmin(提供HTTPS服务)
查看>>
vi 常用命令
查看>>
关于学习目标和计划
查看>>
solr
查看>>
SVN 配置
查看>>
Footer固定在底部
查看>>
Vsftpd服务搭建
查看>>
直接访问摄像头的原始数据
查看>>
1.3Windows控制台的简单操作:
查看>>
Python、大数据、人工智能、机器学习资料分享(不定期更新)
查看>>
win7 安装mac
查看>>
不知道如何设定高度
查看>>
小议数据加密解密
查看>>
nagios配置文件详解
查看>>
wireshark
查看>>
深入查询表达式
查看>>