用JAVA编写一个算法实现对一个字符数组的所有元素的所有组合

看到一个java的面试题,题目如下:
编写一个算法,输入任意长度的一个字符数组,返回这个数组元素的所有组合:例如输入[a,b,c],返回[[],[a],[b],[c],[a,b],[a,c],[b,c],[a,b,c]]。
当时看到这个题目的第一想法是通过递归的方法,从没个数组的长度分析然后得出结果;但是试验了很久都没有成功,如果输入四个字符的数组的话,然后返回几个只有三个字符的数组还是正确的,但是想要再得到两个字符的数组就不对了,恕我愚钝,后来在网上看到其实递归也能实现的,但是我没有深追,因为我看到一个更好的办法;所以现在给大家分享如下:
先贴代码:

public class Test {

    public static void main(String[] args) {
        String[] a = new String[] { "a", "b", "c", "d" };
        List<String> list = Arrays.asList(a);
        List<List<Object>> aa = str(list);
        for(List<Object> ss:aa){
            for(Object s:ss){
                System.out.print(s+",");
            }
            System.out.println();
        }
    }
    public static List<List<Object>> str(List<String> list) {
        List<List<Object>> result = new ArrayList<List<Object>>();
        long n = (long)Math.pow(2,list.size());
        List<Object> combine;
        for (long l=0L; l<n; l++) {
            combine = new ArrayList<Object>();
            for (int i=0; i<list.size(); i++) {
                if ((l>>>i&1) == 1)
                    combine.add(list.get(i));
            }
            result.add(combine);
        }
        return result;
    }
}
打印结果为:

a,
b,
a,b,
c,
a,c,
b,c,
a,b,c,
d,
a,d,
b,d,
a,b,d,
c,d,
a,c,d,
b,c,d,
a,b,c,d,

看结果,包括最上面的一个空的,刚好16个,接下来分析。
如果像我这种初学者看确实有些蒙,我也是看了很久才明白,所以在这儿记下来方便以后更快的看懂。
这里首先是得到传入字符串的所有组合的数量,即2的n次方,n是数组的长度;也就是上面说道的刚好16个组合。其实想到这一步并不难,有点数学常识的都应该知道,但是为了得到所有组合的时候就有点没有头绪了,而在这个方法中对于我们来说比较陌生但却是最关键的东西就是”>>>”这个符号了,什么意思呢?——无符号右移,而那个if中的意思就是将l无符号右移i位然后再和1去&得到的看是不是等于1;这里是二进制的右移,同样和1相与也是二进制的。其实到这里还是比较不懂为什么要把0-15这16个数要拿来分别去无符号右移i位,然后我就拿来笔记本了:

十进制二进制
00000
10001
20010
30101
40100
50101
60110
70111
81000
91001
101010
111011
121100
131101
141110
151111

有没有一点顿悟?如果把二进制的四位看成我们传入的a,b,c,d的话,而且每位是1的话就显示,是0就不显示。这样得到的16位是不是就是所有组合了。
而且这个排列刚刚是前面得出答案的很类似,只是顺序反了而已。而刚刚那无符号右移也很简单解释了,就是去判断对应的i位上是不是1。这个方法其实看懂了过后就很容易记住而且容易理解。所以在这里分享啦;看到这儿就点一个顶吧,谢谢。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值