二进制状态压缩枚举子集


  

引言:

二进制数可以用来表示一个状态,比如当我们需要去表示一个集合的子集时,可以用二进制数来表示该子集。

问题

  比如有一个集合,集合中的元素为 {1, 5, 7, 9, 12},如何快速找到其所有的子集合呢。这就可以采用二进制来压缩该集合,并枚举其所有的子集合状态。

方法一:先二进制压缩,再枚举

public class BinaryStateEnumTest {
    @Test
    public void test() {
        int[] set = {7, 5, 1, 9, 12};
        int binary = 0b100101010001;//12位二进制数。将该集合压缩成一个二进制数。该二进制数从右往左非零元素所在位置对应set中的数

        int status = binary;//最多只有 2^set.length 种状态,每个状态对应一个set的子集
        do {
            System.out.println(getBinaryString(status));
            status = (status - 1) & binary;
        } while (status != binary);//枚举状态包括0,即0b000000000000

        System.out.println("*******************************");

        do {
            System.out.println(getBinaryString(status));
            status = (status - 1) & binary;
        } while (status != 0);//枚举状态不包括0
    }

    private String getBinaryString(int number) {//保证输出长度为12位
        StringBuilder sb = new StringBuilder(Integer.toBinaryString(number));
        while (sb.length() < 12) sb.insert(0, '0');
        return sb.toString();
    }
}

方法二:直接二进制枚举

public class BinaryStateEnumTest {
    @Test
    public void test() {
        int[] set = {7, 5, 1, 9, 12};
        int length = set.length;

        //枚举其子集状态
        for (int i = 0, status = 0; i < (1 << length); i++) {
            for (int j = 0; j < length; j++) {
                if ((i & (1 << j)) != 0) {
                    status |= (1 << set[j] - 1);//最多左移11位,所以是一个12位二进制
                }
            }
            //status是一个12位二进制数表示的状态
            System.out.println(getBinaryString(status));//枚举状态包括0,即0b000000000000
        }

        System.out.println("*********************");

        for (int i = 1, status = 0; i < (1 << length); i++) {
            for (int j = 0; j < length; j++) {
                if ((i & (1 << j)) != 0) {
                    status |= (1 << set[j] - 1);
                }
            }
            System.out.println(getBinaryString(status));//枚举状态不包括0
        }
    }

    private String getBinaryString(int number) {//保证输出长度为5位
        StringBuilder sb = new StringBuilder(Integer.toBinaryString(number));
        while (sb.length() < 12) sb.insert(0, '0');
        return sb.toString();
    }
}

文章作者: YangChongZhi
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 YangChongZhi !
评论
 上一篇
快速排序模板 快速排序模板
   引言: 快速排序由于排序效率在同为O(N*logN)的几种排序方法中效率较高,因此经常被采用。 说明  快速排序算法经常被采用,而且快速排序也采用了分治的思想,因此很多软件公司的笔试面试,包括像腾讯,微软等知名IT公司都喜欢考这个,
2021-03-03
下一篇 
并查集模板 并查集模板
   引言: 关于“并查集”的解释和使用场景网上有很多教程,这里就不在啰嗦了。仅提供代码模板方便知情人快速使用。 并查集的java实现// 开启了路径压缩和按秩合并的并查集 class UnionFind { int n
2021-02-14
  目录