【问题标题】:how to type Permutation for a given string in C# [duplicate]如何在 C# 中为给定字符串键入 Permutation [重复]
【发布时间】:2012-12-08 15:46:05
【问题描述】:

可能重复:
How to type sets for a given string

我正在尝试键入字符串的排列 例如字符串“123”应该给我 123 132 213 231 321 312 我需要帮助来修复我的代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestAAD
{
class Program
{
    static int len = 0;
    static int lenPerm = 0;
    private static void Permutations(string str, string perm , int i)
    {
        if (i == len) Console.WriteLine(perm);
        for (int k = 0; k < len; k++)
        {
             lenPerm = perm.Length;
            for (int j = 0; j < lenPerm; j++)
            {
                if ((perm[j] == str[(len - 1) - k]) && (len-1-k>0))
                    k++;
            }
            if((len-1-k) >=0)
            Permutations(str, perm + str[(len - 1) - k], i++);
        }
    }
    static void Main(string[] args)
    {
        string st = "123";
        len = st.Length;
        Permutations(st, "",0);
    }
}
}

如果有人可以帮助我,请 谢谢大家

【问题讨论】:

  • 这有助于显示您的代码究竟在哪里失败。它已经做了什么,它在哪里不起作用?具体是什么问题?并且:您尝试过什么解决问题的方法?
  • 它给了我 stackOverFlowException
  • 如果您需要帮助了解为什么您的代码不起作用,那么不要连续问 3 个问题如何实现所需的行为。相反,请尝试找出问题所在,报告您不了解的问题,指出代码的相关部分,也许那么我们可以帮助您。我标记这个帖子。连续 3 个完全相同的问题,而根本没有努力改进您的问题,这只是在浪费每个人的时间。

标签: c# recursion permutation backtracking


【解决方案1】:

排列很容易做到。

public string[] FindPermutations(string word)
{
    if (word.Length == 2)
    {
        char[] c = word.ToCharArray();
        string s = new string(new[] { c[1], c[0] });
        return new[]
            {
                word,
                s
            };
    }

    List<string> result = new List<string>();

    string[] subsetPermutations = FindPermutations(word.Substring(1));
    char firstChar = word[0];
    foreach (string temp in subsetPermutations
                    .Select(s => firstChar.ToString(CultureInfo.InvariantCulture) + s))
    {
        result.Add(temp);
        char[] chars = temp.ToCharArray();
        for (int i = 0; i < temp.Length - 1; i++)
        {
            char t = chars[i];
            chars[i] = chars[i + 1];
            chars[i + 1] = t;
            string s2 = new string(chars);
            result.Add(s2);
        }
    }
    return result.ToArray();
}

【讨论】:

    【解决方案2】:

    Permutations 在循环中再次调用Permutations len 次。这第二个Permutations 调用再次循环调用Permutations len 次。这种情况会无休止地一次又一次地发生,或者至少在您遇到堆栈溢出之前发生。

    当您使用递归调用时,您必须始终确保递归在某处停止。

    If (job not done) {
        make recursive call
    }
    

    递归调用必须朝着完成工作迈出一步,否则它永远不会完成。


    UPDATE 1(仅解决异常问题)

    该方法难以阅读。不要多次重复表达式len-1-k,而是反转循环! for (int k = str.Length - 1; k &gt;= 0; k--) 并在内部循环中使用 k-- 减少 k。我也去掉了多余的变量len

    在您的实现中,len-1-k 始终是&gt;= 0。因此递归调用永远不会结束。因此我改变了减少k的条件。即使它已经是0,它也会减少k。为了避免在str[k] 中出现获取索引越界错误,必须首先检查条件k &gt;= 0

    private static void Permutations(string str, string perm, int i)
    {
        if (i == str.Length)
            Console.WriteLine(perm);
        for (int k = str.Length - 1; k >= 0; k--) {
            int lenPerm = perm.Length;
            for (int j = 0; j < lenPerm; j++) {
                if (k >= 0 && perm[j] == str[k])
                    k--;
            }
            if (k >= 0)
                Permutations(str, perm + str[k], i++);
        }
    }
    
    public static void Start()
    {
        string st = "123";
        Permutations(st, "", 0);
    }
    

    这不再产生无限递归,但结果仍然不正确。我让你弄清楚如何进一步改进代码。


    更新 2(创建正确的排列)

    最后是我的工作实现

    public static class PermutationBuilder
    {
        private static char[] _characters;
        private static List<string> _list;
    
        public static IEnumerable<string> GetPermutations(string characters)
        {
            _characters = characters.ToCharArray();
            _list = new List<string>();
            AddPermutations("", 0);
            return _list;
        }
    
        private static void AddPermutations(string permutation, int level)
        {
            if (level >= _characters.Length) {
                _list.Add(permutation);
            } else {
                for (int i = 0; i < _characters.Length; i++) {
                    char ch = _characters[i];
                    if (ch != ' ') {
                        _characters[i] = ' ';
                        AddPermutations(permutation + ch, level + 1);
                        _characters[i] = ch;
                    }
                }
            }
        }
    }
    

    请注意,我暂时用空格字符标记了已使用的字符。

    你这样称呼它

    foreach (string permutation in PermutationBuilder.GetPermutations("123")) {
        Console.WriteLine(permutation);
    }
    

    【讨论】:

    • 但我试图通过增加 k 来打破循环
    • if ((perm[j] == str[(len - 1) - k]) && (len-1-k>0)) k++;
    • @user1816808 鉴于您获得了StackOverflowException,您认为您能够打破循环吗?尝试调试,看看会发生什么。
    • if 之后的递归调用没有缩进。因此,我没有看到 if 保护它。
    • 谢谢,但现在代码给了我“abc”:ab abc abcb abcba 和字符串“ab”没有结果,如果你知道任何算法来输入排列,我会很感激你.
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-22
    • 2017-01-08
    • 1970-01-01
    相关资源
    最近更新 更多