【问题标题】:Printing PowerSet with help of bit position借助位位置打印 PowerSet
【发布时间】:2014-07-11 07:57:06
【问题描述】:

谷歌搜索了一段时间以查找字符串的子集,我阅读了 wikipedia ,它提到了

.....对于 S 的整个幂集,我们得到:

{ } = 000 (Binary) = 0 (Decimal)
{x} = 100 = 4
{y} = 010 = 2
{z} = 001 = 1
{x, y} = 110 = 6
{x, z} = 101 = 5
{y, z} = 011 = 3
{x, y, z} = 111 = 7

有没有办法通过程序来实现,避免使用字符串长度的递归算法?

到目前为止我的理解是,对于长度为 n 的字符串,我们可以从 0 运行到 2^n - 1 并打印 on 位的字符。
我无法得到的是如何以最优化的方式将那些 on 位与相应的字符映射

PS : 已检查线程但无法理解这一点和 c++ : Power set generated by bits

【问题讨论】:

  • 嗨,我目前没有时间,但我想稍后与您讨论。可以分享一下联系方式吗?
  • @Juvanis :这是我在 SO 上看到的最令人惊叹的评论......一开始不知道该回复什么 :) 当你有时间时放弃答案......不要着急伴侣!!或LinkedIn URL,如果适合您,我可以提供:)
  • 请考虑将答案之一标记为正确。

标签: java algorithm subset bit powerset


【解决方案1】:

这个想法是,一组大小为 n 的幂集恰好有 2^n 个元素,与最多 n 个长度不同的二进制数完全相同。

现在您所要做的就是在两者之间创建一个映射,而您不需要递归算法。幸运的是,对于二进制数,您有一个真正直观和自然的映射,如果您的循环变量设置了位 j,您只需将字符串中位置 j 的字符添加到子集中,您可以使用 getBit() 轻松完成此操作。写在那里(你可以内联它,但我为你做了一个单独的函数以提高可读性)。

附注根据要求,更详细的映射说明: 如果您有递归算法,则您的流程由您在递归调用中遍历数据结构的方式给出。这是解决许多问题的一种非常直观和自然的方式。

如果您出于某种原因想在不使用递归的情况下解决此类问题,例如使用更少的时间和内存,那么您将面临明确的遍历这一艰巨任务。

当我们使用带有循环变量的循环时,该循环变量假定一组值,我们需要确保映射循环变量的每个值,例如42,到一个元素,在我们的例子中是s 的子集,在某种程度上我们有一个双射映射,也就是说,我们只映射到每个子集一次。因为我们有一套顺序并不重要,所以我们只需要满足这些要求的任何映射。

现在我们看一个二进制数,例如42 = 32+8+2 和上面位置的二进制一样:

543210
101010

因此,我们可以使用以下位置将 42 映射到子集:

  • 以任何您喜欢但一致的方式对集合 s 的元素进行排序(在一个程序执行中始终相同),在我们的例子中,我们可以使用字符串中的顺序
  • 当且仅当位置 j 的位已设置(等于 1)时,才添加元素 e_j

由于每个数字至少有一个数字与其他数字不同,我们总是得到不同的子集,因此我们的映射是单射的(不同的输入 -> 不同的输出)。

我们的映射也是有效的,因为我们选择的二进制数的长度最多等于我们集合的大小,因此位位置总是可以分配给集合中的一个元素。结合我们的输入集被选择为具有与幂集大小相同的大小 (2^n) 的事实,我们可以得出它实际上是双射的。

import java.util.HashSet;
import java.util.Set;

public class PowerSet
{

    static boolean getBit(int i, int pos) {return (i&1<<pos)>0;}

    static Set<Set<Character>> powerSet(String s)
    {
        Set<Set<Character>> pow = new HashSet<>();
        for(int i=0;i<(2<<s.length());i++)
        {
            Set<Character> subSet = new HashSet<>();
            for(int j=0;j<s.length();j++)
            {
                if(getBit(i,j)) {subSet.add(s.charAt(j));}
            }
            pow.add(subSet);
        }
        return pow;

    }

    public static void main(String[] args)
    {System.out.println(powerSet("xyz"));}

}

【讨论】:

  • 来自Fortunately..........there ,你写的一切都没有中断,我无法理解,你能改写一下让 Noob 理解吗! :)
【解决方案2】:

这是一种简单的方法(伪代码):-

for(int i=0;i<2^n;i++) {

  char subset[];
  int k = i;
  int c = 0;
  while(k>0) {

    if(k%2==1) {
       subset.add(string[c]);
    }
    k = k/2;
    c++;
  } 

  print subset;
}

解释:- 代码将数字除以 2 并计算余数,用于将数字转换为二进制形式。然后如您所知,仅选择该位编号为 1 的字符串中的索引。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-31
    • 2016-05-29
    • 1970-01-01
    • 2011-03-29
    • 2023-02-07
    • 2021-10-19
    • 2012-12-17
    相关资源
    最近更新 更多