【问题标题】:All possible distinct subsets of characters in a given string JAVA给定字符串 JAVA 中所有可能的不同字符子集
【发布时间】:2016-01-22 00:12:57
【问题描述】:

正如标题所说,我需要执行以下操作。但不知何故我得到了错误的答案,也许循环有问题?

这是我到目前为止编写的代码,但它似乎给了我错误的结果。有什么想法、帮助、提示、修复吗?

import java.util.ArrayList;

public class pro1
{
private String lettersLeft;
private ArrayList<String> subsets;

public pro1(String input)
{
    lettersLeft = input;
    subsets = new ArrayList<String>();
}

public void createSubsets()
{       
    if(lettersLeft.length() == 1)
    {
        subsets.add(lettersLeft);
    }
    else
    {
        String removed = lettersLeft.substring(0,1);
        lettersLeft = lettersLeft.substring(1);
        createSubsets();
        for (int i = 0; i <= lettersLeft.length(); i++)
        {
            String temp = removed + subsets.get(i);
            subsets.add(temp);
        }
        subsets.add(removed);
    }
}

public void showSubsets()
{
    System.out.print(subsets);
}
}

我的测试班在这里:

public class pro1
{
public static void main(String[] args) 
{
    pro1s = new pro1("abba");
    s.createSubsets();
    s.showSubsets();
}
}

【问题讨论】:

  • 我认为使用另一种方法更简单 - 如果字符串 X 的长度,生成 1 到 2**X 之间的所有数字 - 1。如果在二进制表示中位设置为 1 - 使用它作为元素的索引现有子集。
  • 肯定有9个,不是11个,你只列出了10个,aba不是abba的子串?
  • @Adam 你是对的,计数错误(应该是 10),但请注意,他要求的是子集而不是子串。从他想要的输出中,很明显他想要字符串中有序字符集的唯一有序子集。
  • @Matthew 是的,抱歉,我看错了问题

标签: java string function recursion subset


【解决方案1】:

试试

int numSubsets = (int)java.lang.Math.pow(2,toSubset.length());
for (int i=1;i<numSubsets;i++) {
    String subset = "";
    for (int j=0;j<toSubset.length();j++) {
        if ((i&(1<<j))>0) {
            subset = subset+toSubset.substring(j,j+1);
        }
    }
    if (!subsets.contains(subset)) {
        subsets.add(subset);
    }
}

其中toSubset 是您希望子集化的字符串(在您的示例中为String toSubset="abba"),subsets 是包含结果的ArrayList。

为此,我们实际上迭代了幂集(所有子集的集合),其大小为 2^A,其中 A 是原始集的大小(在本例中为字符串的长度)。

每个子集可以用 0 到 2^A-1 的数字唯一标识,其中第 j 位的值(索引为 0)指示该元素是否存在,1 表示存在,0 表示不存在。请注意,数字 0 表示对应于空集的二进制字符串 00...0。因此我们从 1 开始计数(您的示例没有将空集显示为所需的子集)。

对于每个值,我们通过查看每个位位置并使用按位算术确定它是 1 还是 0 来构建一个子集字符串。 1&lt;&lt;j 是第 j 个二进制位置为 1 的整数,i&amp;(i&lt;&lt;j) 是仅在两个整数都有 1 的位置为 1 的整数(因此,根据 i 在第 j 个二进制位置是否为 1 为 0 或 1数字)。如果 i 在第 j 个二进制数字中有 1,我们附加字符串的第 j 个元素。

最后,当您要求唯一子集时,我们检查是否已经使用了该子集,如果没有,我们将其添加到 ArrayList。

【讨论】:

    【解决方案2】:

    在使用递归时,很容易让你头脑发热。一般来说,我怀疑你的问题是你在递归兔子洞的路上存储的一个字符串,以便在备份的路上使用是一个类成员变量,你的递归方法是同一个类的方法。尝试在 createSubsets() 方法中将 lettersLeft 设为局部变量。比如:

    public class Problem1
    {
    private String originalInput;
    private ArrayList<String> subsets;
    
    public Problem1(String input)
    {
        originalInput = input;
        subsets = new ArrayList<String>();
    }
    
    // This is overloading, not recursion.
    public void createSubsets()
    {    
        createSubsets(originalInput);
    }
    public void createSubsets(String in)
    {       
        if(in.length() == 1)
        {
            // this is the stopping condition, the bottom of the rabbit hole
            subsets.add(in);
        }
        else
        {
            String removed = in.substring(0,1);
            String lettersLeft = in.substring(1);
    
            // this is the recursive call, and you know the input is getting
            // smaller and smaller heading toward the stopping condition
            createSubsets(lettersLeft);
    
            // this is the "actual work" which doesn't get performed
            // until after the above recursive call returns
            for (int i = 0; i <= lettersLeft.length(); i++)
            {
                // possible "index out of bounds" here if subsets is 
                // smaller than lettersLeft
                String temp = removed + subsets.get(i);
                subsets.add(temp);
            }
            subsets.add(removed);
        }
    }
    

    在遍历代码时要记住一些事情,试图思考它将如何运行......您已经构建了递归方法,使得执行指针在执行任何“实际工作”之前一直沿着递归兔子洞向下移动",只需从输入中拉出字母并将它们推入堆栈。当字母从堆栈中弹出时,所有“真正的工作”正在从兔子洞中返回。因此,子集列表中的第一个“a”实际上是输入字符串“abba”中的最后一个“a”。 IE。添加到子集列表的第一个字母是因为lettersLeft.length() == 1。 (在我的示例中为in.length() == 1)。此外,调试器是您的朋友。分步调试是一种很好的方法,可以验证您的代码在整个过程中的每一步是否确实按照您的预期进行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-12-07
      • 1970-01-01
      • 2021-02-02
      • 2018-06-29
      • 2017-07-04
      • 2012-10-24
      相关资源
      最近更新 更多