【问题标题】:Create a Set of lists from two lists through recursion通过递归从两个列表创建一组列表
【发布时间】:2017-05-08 15:57:40
【问题描述】:

我已经在这个网站上搜索了许多问题,其中有一些类似的基本概念,但是在尝试自己解决这个问题并进行审查之后几个小时我仍然迷路了.如果还有其他问题可以回答这个问题,我将非常乐意给它看看。

最终我想创建一个递归方法,它需要两个列表并返回一个字符串列表集

//Example of such a function definition
private static Set<List<String>> myRecursiveMethod(List<String> listOne, 
List<String> listTwo) {
}

当我说“字符串列表集”时,我的意思是具体如下: (注:"AD" == "DA")

// if the two following lists are INPUTTED into myRecursiveMethod();
// listOne = ["A","B"]
// listTwo = ["C","D"]
// the following set is OUTPUTTED: [["AC","BD"],["AD","BC"]] 

如果listOne 和listTwo 中都有三个元素,那么集合中将有六个元素。即:

// listOne = ["A","B","C"]
// listTwo = ["D","E","F"]
// OUTPUTTED: [["AD","BE","CF"],["AD","BF","CE"],["BD","AE","CF"],
// ["BD","AF","CE"],["CD","AE","BF"],["CD","AF","BE"]] 

我尝试使用双重增强的 FOR 循环编写此代码,以便理解逻辑。我的 FOR 循环方法很糟糕,适用于 list.size() == 2 的硬编码限制。

// Create Lists and append elements 
List<String> listOne = new ArrayList<String>();
listOne.add("A");
listOne.add("B");

List<String> listTwo = new ArrayList<String>();
listTwo.add("C");
listTwo.add("D");

// List One = ["A","B"]
// List Two = ["C","D"]

// Create new List
List<List<String>> newList = new ArrayList<List<String>>();
Integer counter = 0;

    for (String s : listOne) {
        counter++;
        for (String p : listTwo) {

            // A HARD-CODED bad implementation of this method
            if (counter < 3) {
                List<String> newListTwo = new ArrayList<String>();
                newListTwo.add(s.concat(p));
                newList.add(newListTwo);

            } else if (!(counter % 2 == 0)) {
                newList.get(1).add(s.concat(p));

            } else {
                newList.get(0).add(s.concat(p));
            }
        }
    }
    System.out.println(newList); // = [["AC","BD"],["AD","BC"]] 

您还可以注意到,我定义了 List> 而不是 Set>。这是由于我的错误编码尝试依赖于 list.get() 方法。

所以我目前的递归方法如下:

private static Set<List<String>> myRecursiveMethod(List<String> listOne, 
List<String> listTwo) 
{
    //Base Case:
    if (listOne.isEmpty){
        return new HashSet<List<String>>;
    }
    //Recursive Case:
    else {
        String listOneFirst = listOne.get(0);
        String listTwoFirst = listTwo.get(0);

        List<String> sampleList = new ArrayList<String>();
        sampleList.add(listOneFirst+listTwoFirst);

        Set<List<String>> newSet = new HashSet<List<String>>(myRecursiveMethod())
        newSet.add(sampleList);
        return newSet;
    }
}

这个方法目前只能这样操作:

输入:

  • 列表一 = ["A","B"]
  • 列表二 = ["C","D"]

输出:

  • [[“AC”][“BD”]]

期望的输出:

  • [["AC","BD"],["AD","BC"]]

编辑:

查看回复后,我的班级 W.I.P 代码:

private static Set<List<String>> myRecursiveMethod(List<String> listOne,
        List<String> listTwo) {

    //Backup Case (user enters an empty list)
    if (listOne.isEmpty()){
        return new HashSet<List<String>>();
    }

    // Base Case:
    if (listOne.size() == 1) {
        List<String> mergedStrings = new ArrayList<>();
        for (String s : listTwo) {
            mergedStrings.add(listOne.get(0).concat(s));
        }
        Set<List<String>> builtHashSet = new HashSet<List<String>();
        builtHashSet.add(mergedStrings);
        return builtHashSet;
    }
    // Recursive Case:
    else {

        // Ensure original list values arn't changed.
        List<String> newListOne = new ArrayList<String>(listOne);
        List<String> newListTwo = new ArrayList<String>(listTwo);

        //first two elements...I don't think this is correct
        String listOneFirst = newListOne.get(0);
        String listTwoFirst = newListTwo.get(0);
        List<String> sampleList = new ArrayList<String>();
        sampleList.add(listOneFirst + listTwoFirst);

        //used for making recursive case smaller
        newListOne.remove(0);

        // Calls recursion
        Set<List<String>> newSet = new HashSet<List<String>>(
                myRecursiveMethod(newListOne, newListTwo));
        newSet.add(sampleList);

        return newSet;
    }
}

【问题讨论】:

  • 只是为了理解那个细节:这是作业,你被要求创建一个递归方法?因为我认为非递归方法应该是直截了当的......
  • 这不是直接的课程。我正在使用它来加深我在递归方面的知识,并且我基于一个 similar question 我之前被问过但从未能够解决的方法。
  • 我并不认为这里需要递归,因为输入参数的数量总是固定的 (2)。如果我正确理解生成字符串的规则,则有两个步骤:找到第二个列表项的所有排列,然后将它们与第一个列表中的元素连接起来。迭代在这里非常好;如果你把它分成两个步骤,你应该能够解开它并轻松使它与列表的长度无关。
  • 在这种情况下,也许这可以帮助您:stackoverflow.com/a/10305419/7653073。这是一种生成列表排列的递归方法。
  • 现实生活应用程序中,我绝对会使用迭代来解决这个问题,因为它对我来说最有意义。但是,我想从以前无法解决的问题中学习,因此。 @MalteHartwig 感谢您提供的链接,我现在就来看看。

标签: java recursion set


【解决方案1】:

我认为问题出在这里:

if (listOne.isEmpty){
    return new HashSet<List<String>>;
}

您是对的,在某些时候您的递归必须结束,并且您必须开始构建所需的输出。但所需的输出不是带有空列表的 Set。它是一个包含一些列表和一些内容的集合。因此:不要等到 listOne 为空。而是:

if (listOne.size() == 1) {
  List<String> mergedStrings = new ArrayList<>();
  mergedStrings = ... merge the ONE listOne entry with all listTwo entries
  Set<List<String>> rv = new HashSet<>();
  rv.add(mergedStrings);
  return rv;
}

换句话说:您使用递归将第一个列表的长度减一。当该列表中只剩下 一个 元素时,就该合并到第二个列表中了。

现在让我们看看如何“使用”它(为简洁起见,调用方法 rec );放下一些伪代码来显示我们需要的步骤:

rec([a, b], [c,d]) -->
rec([a], [c,d]) X rec([b], [c, d]) -->
<[ac, ad]> X <[bc, bd]> -->
<[ac, ad], [bc, bd]>

“X”表示“加入”递归调用的两个结果;应该很简单:

Set<List<String>> rec1 = rec(...);
return rec1.addAll(rec2 ...

【讨论】:

  • 我现在试试,看看效果如何。
  • 通过我的 mergedStrings 遵循这个成为所有可能的 listOne 条目 + listTwo 条目的单个列表:for (String s : listTwo) { mergedStrings.add(listOne.get(0).concat(s)); } 但是,如果我想要任何条目(即 A、B、C或 D) 只发生一次 与单个列表对象我被困在我要递归的东西上。我添加了我的新代码的更新(不确定这是否是问题的标准程序)。
  • 谢谢@GhostCat,帮了大忙,有时间我会去看看的:)
  • 哦,对了,我对整个服务还是新手,会的。
猜你喜欢
  • 2020-04-08
  • 2018-03-10
  • 2014-06-29
  • 2021-05-18
  • 2022-12-08
  • 2020-02-27
  • 2022-10-18
  • 2012-08-23
  • 2016-09-07
相关资源
最近更新 更多