How do I go through every single anagram of name's initials using recursion without using any type of loop?

huangapple go评论90阅读模式
英文:

How do I go through every single anagram of name's initials using recursion without using any type of loop?

问题

以下是已翻译的内容:

这是我目前所得到的...

我希望它的效果就像这样,如果首字母是ABC:

ABC
ACB
BAC
BCA
CAB
CBA

... 但是我似乎无法实现它。

import java.util.*;

public class Anagram {

    public static String swap(String n) {
        int count = n.length();
        char[] temp = n.toCharArray();
        int in_pos = 0;
        
        if (counter(count) == 1) {
            return "Thank you!";
        } else {
            counter(count);
            String s = String.valueOf(temp);
            return swap(s);
        }
        
    }
    
    public static int counter(int c) {
        
        if (c == 0) {
            return 1;
        } else {
            return c * counter(c - 1);
        }
    }
    
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        System.out.print("Full Name: ");
        String name_full = in.nextLine();
        System.out.print("Enter the initials of your full name: ");
        String name_initials = in.nextLine();
        String rep_space = name_initials.replaceAll("\\s", "");

        System.out.println(swap(rep_space));
    }
}
英文:

Here's what I got so far...

I want it to be like if the initials were ABC:

ABC
ACB
BAC
BCA
CAB
CBA

... but I can't seem to make it happen.

import java.util.*;

public class Anagram {

	public static String swap(String n) {
		int count = n.length();
		char[] temp = n.toCharArray();
		int in_pos = 0;
		
		if(counter(count) == 1) {
			return "Thank you!";
		}else {
			counter(count);
			String s = String.valueOf(temp);
			return swap(s);
		}
		
	}
	
	public static int counter(int c) {
		
		if(c == 0) {
			return 1;
		}else {
			return c*counter(c-1);
		}
	}
	
	
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		System.out.print("Full Name: ");
		String name_full = in.nextLine();
		System.out.print("Enter the initials of your full name: ");
		String name_initials = in.nextLine();
		String rep_space = name_initials.replaceAll("\\s", "");
		
		System.out.println(swap(rep_space));
	}
}

答案1

得分: 1

这个回答假设字符串中的字母是唯一的。否则,为了防止重复的变位词,需要进行修改。

编写一个变位词函数的一种方法是循环遍历每个字符 c,递归地计算其他字母的变位词,并将子变位词附加到每个 c 上。基本情况是当字符串只有一个字符时。

例如,这里是一个 Java 实现:

import java.util.ArrayList;
import java.util.List;

public class Anagrams {
    public static List<String> anagrams(String s) {
        List<String> output = new ArrayList<String>();
        if (s.length() == 0)
            return output;
        if (s.length() == 1) {
            output.add(s);
            return output;
        }
        for (int i = 0; i < s.length(); ++i) {
            String c = s.substring(i, i + 1);
            // 从字符串 s 中移除字符 c,形成字符串 s2
            String s2 = s.substring(0, i) + s.substring(i + 1);
            // 计算 s2 的变位词,并将每个附加到字符 c
            List<String> anagrams2 = anagrams(s2);
            for (String anagram : anagrams2) {
                output.add(c + anagram);
            }
        }
        return output;
    }
    
    public static void main(String[] args) {
        List<String> l = anagrams("abc");
        for (String s : l) {
            System.out.println(s);  // abc, acb, bac, bca, cab, cba
        }
    }
}

然而,如此编写的方法不符合不使用任何循环的限制。可以将解决方案调整为使用递增索引递归地替换 for 循环,基本情况是索引越界时。

例如,这里是一个 Java 实现,后面详细介绍了如何将 for 循环转换为相应的递归函数:

import java.util.ArrayList;
import java.util.List;

public class Anagrams {
    public static List<String> anagrams(String s) {
        List<String> output = new ArrayList<String>();
        if (s.length() == 0)
            return output;
        if (s.length() == 1) {
            output.add(s);
            return output;
        }
        // 递归地迭代字符
        class CharIter {
            public void run(int char_idx) {
                if (char_idx >= s.length())
                    return;
                String c = s.substring(char_idx, char_idx + 1);
                // 从字符串 s 中移除字符 c,形成字符串 s2
                String s2 = s.substring(0, char_idx) + s.substring(char_idx + 1);
                // 计算 s2 的变位词,并将每个附加到字符 c
                List<String> anagrams2 = anagrams(s2);
                // 递归地迭代子变位词
                class AnagramIter {
                    public void run(int anagram_idx) {
                        if (anagram_idx >= anagrams2.size())
                            return;
                        output.add(c + anagrams2.get(anagram_idx));
                        run(anagram_idx + 1);
                    }
                }
                new AnagramIter().run(0);
                run(char_idx + 1);
            }
        }
        new CharIter().run(0);
        return output;
    }
    
    public static void main(String[] args) {
        List<String> l = anagrams("abc");
        for (String s : l) {
            System.out.println(s);  // abc, acb, bac, bca, cab, cba
        }
    }
}

将循环转换为递归函数

对于每个转换后的循环,终止循环的条件被用作递归函数的基本情况,循环体被用作递归函数的主体。为了传达这个想法,下面的示例展示了如何使用 for 循环和递归函数来打印 03 之间的整数。

public class Loop {
    private static int NUM_LOOPS = 4;
    
    // 迭代循环
    private static void loop_iter() {
        for (int i = 0; i < NUM_LOOPS; ++i) {
            System.out.println(i);
        }
    }
    
    // 递归循环
    private static void loop_rec(int i) {
        if (i >= NUM_LOOPS)
            return;
        System.out.println(i);
        loop_rec(i + 1);
    }
    
    public static void main(String[] args) {
        loop_iter();  // 输出 0, 1, 2, 3
        System.out.println();
        loop_rec(0);  // 输出 0, 1, 2, 3
    }
}

因为函数调用需要额外的堆栈内存,递归方法会比迭代方法使用更多的堆栈内存。一些语言(如 Scheme)利用尾调用优化,使得递归尾调用不使用额外的堆栈空间,但 Java 不是这种情况。

英文:

This answer makes the assumption that the letters in the string are unique. Modifications would be required to prevent repeated anagrams otherwise.

One way to write an anagram function is to loop over each character c, recursively calculating the anagrams for the other letters, and appending the sub-anagrams to each c. The base case is when the string is only one character.

For example, here's a Java implementation:

import java.util.ArrayList;
import java.util.List;

public class Anagrams {
    public static List&lt;String&gt; anagrams(String s) {
        List&lt;String&gt; output = new ArrayList&lt;String&gt;();
        if (s.length() == 0)
            return output;
        if (s.length() == 1) {
            output.add(s);
            return output;
        }
        for (int i = 0; i &lt; s.length(); ++i) {
            String c = s.substring(i, i + 1);
            // Remove char c from string s to form string s2
            String s2 = s.substring(0, i) + s.substring(i + 1);
            // Calculate anagrams of s2 and append each to char c
            List&lt;String&gt; anagrams2 = anagrams(s2);
            for (String anagram : anagrams2) {
                output.add(c + anagram);
            }
        }
        return output;
    }
    
    public static void main(String[] args) {
        List&lt;String&gt; l = anagrams(&quot;abc&quot;);
        for (String s : l) {
            System.out.println(s);  // abc, acb, bac, bca, cab, cba
        }
    }
}

However, as is, that approach doesn't satisfy the constraint to not use any loops. The solution can be adapted to replace the for loops with functions that recursively increment an index, with the base case being when the index goes out-of-bounds.

For example, here's a Java implementation, followed by details on converting for loops to corresponding recursive functions.

import java.util.ArrayList;
import java.util.List;

public class Anagrams {
    public static List&lt;String&gt; anagrams(String s) {
        List&lt;String&gt; output = new ArrayList&lt;String&gt;();
        if (s.length() == 0)
            return output;
        if (s.length() == 1) {
            output.add(s);
            return output;
        }
        // Recursively iterate over characters
        class CharIter {
            public void run(int char_idx) {
                if (char_idx &gt;= s.length())
                    return;
                String c = s.substring(char_idx, char_idx + 1);
                // Remove char c from string s to form string s2
                String s2 = s.substring(0, char_idx) + s.substring(char_idx + 1);
                // Calculate anagrams of s2 and append each to char c
                List&lt;String&gt; anagrams2 = anagrams(s2);
                // Recursively iterate over sub-anagrams
                class AnagramIter {
                    public void run(int anagram_idx) {
                        if (anagram_idx &gt;= anagrams2.size())
                            return;
                        output.add(c + anagrams2.get(anagram_idx));
                        run(anagram_idx + 1);
                    }
                }
                new AnagramIter().run(0);
                run(char_idx + 1);
            }
        }
        new CharIter().run(0);
        return output;
    }
    
    public static void main(String[] args) {
        List&lt;String&gt; l = anagrams(&quot;abc&quot;);
        for (String s : l) {
            System.out.println(s);  // abc, acb, bac, bca, cab, cba
        }
    }
}

Converting Loops to Recursive Functions

For each converted loop, the condition for ending the loop was used as the base case of the recursive function, and the body of the loop was used as the body of the recursive function. To convey the idea, the example below shows how both a for loop and a recursive function can be used to print the integers between 0 and 3.

public class Loop {
    private static int NUM_LOOPS = 4;
    
    // Iterative looping
    private static void loop_iter() {
        for (int i = 0; i &lt; NUM_LOOPS; ++i) {
            System.out.println(i);
        }
    }
    
    // Recursive looping
    private static void loop_rec(int i) {
        if (i &gt;= NUM_LOOPS)
            return;
        System.out.println(i);
        loop_rec(i + 1);
    }
    
    public static void main(String[] args) {
        loop_iter();  // Outputs 0, 1, 2, 3
        System.out.println();
        loop_rec(0);  // Outputs 0, 1, 2, 3
    }
}

Because function calls require additional stack memory, the recursive approach would use more stack memory than the iterative approach. Some languages (e.g., Scheme) utilize tail call optimization so that recursive tail calls do not use any additional stack space, but this is not the case for Java.

答案2

得分: 1

不使用任何类型的循环,你可以使用mapreduce方法作为一种递归方式:

List<String> list = List.of("A", "B", "C");
List<List<String>> permutations = IntStream.range(0, list.size())
        // 中间输出,元素位置
        .peek(i -> System.out.print(i + " "))
        // 为每个元素位置准备可能的排列列表
        .mapToObj(i -> list.stream().map(Collections::singletonList)
                // Stream<List<List<String>>>
                .collect(Collectors.toList()))
        // 中间输出,可能的排列列表
        .peek(System.out::println)
        // 将2D列表的流减少为单个2D列表
        .reduce((list1, list2) -> list1.stream()
                // 内部列表对的求和
                .flatMap(inner1 -> list2.stream()
                        // 过滤掉已经存在的元素
                        .filter(inner2 -> !inner1.containsAll(inner2))
                        // 将两个内部列表合并为一个
                        .map(inner2 -> Stream.of(inner1, inner2)
                                .flatMap(List::stream)
                                .collect(Collectors.toList())))
                // 收集为单个2D列表
                .collect(Collectors.toList()))
        // 否则为空列表
        .orElse(Collections.emptyList());

// 最终输出
System.out.println("排列数量:" + permutations.size());
permutations.forEach(System.out::println);

中间输出:

0 [[A], [B], [C]]
1 [[A], [B], [C]]
2 [[A], [B], [C]]

最终输出:

排列数量:6
[A, B, C]
[A, C, B]
[B, A, C]
[B, C, A]
[C, A, B]
[C, B, A]

另请参阅:使用递归进行字符串排列

英文:

Without using any type of loop, you can use map and reduce methods as a kind of recursion:

List&lt;String&gt; list = List.of(&quot;A&quot;, &quot;B&quot;, &quot;C&quot;);
List&lt;List&lt;String&gt;&gt; permutations = IntStream.range(0, list.size())
        // intermediate output, element position
        .peek(i -&gt; System.out.print(i + &quot; &quot;))
        // prepare a list of possible permutations for each element position
        .mapToObj(i -&gt; list.stream().map(Collections::singletonList)
                // Stream&lt;List&lt;List&lt;String&gt;&gt;&gt;
                .collect(Collectors.toList()))
        // intermediate output, list of possible permutations
        .peek(System.out::println)
        // reduce a stream of 2d lists to a single 2d list
        .reduce((list1, list2) -&gt; list1.stream()
                // summation of pairs of inner lists
                .flatMap(inner1 -&gt; list2.stream()
                        // filter out those elements that are already present
                        .filter(inner2 -&gt; !inner1.containsAll(inner2))
                        // merge two inner lists into one
                        .map(inner2 -&gt; Stream.of(inner1, inner2)
                                .flatMap(List::stream)
                                .collect(Collectors.toList())))
                // collect into a single 2d list
                .collect(Collectors.toList()))
        // otherwise an empty list
        .orElse(Collections.emptyList());

// final output
System.out.println(&quot;Number of permutations: &quot; + permutations.size());
permutations.forEach(System.out::println);

Intermediate output:

0 [[A], [B], [C]]
1 [[A], [B], [C]]
2 [[A], [B], [C]]

Final output:

Number of permutations: 6
[A, B, C]
[A, C, B]
[B, A, C]
[B, C, A]
[C, A, B]
[C, B, A]

<sup>See also: String permutations using recursion</sup>

huangapple
  • 本文由 发表于 2020年10月26日 14:19:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/64532305.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定