N位数排序问题的通用解决方法

前两天看到了这篇帖子:看到的两道面试题,里面的第二道题非常有代表性, 所以就用心做了一下。

算法题:一个任意的三位数(个十百位均不相同), 求将个十百重新按不同的顺序组合共有多少个不同的三位数?分别是什么?(C#)  示例:123:123,132,213,231,312,321。

一开始的想法就是写3个 循环就能把答案凑出来,不过要是N位数怎么办要写N个循环吗?所以马上想到了 使用递归来解决问题。每次取一个数字然后再从剩下的数字中拿第一个,然后依 次类推直到拿到最后一个数字结束。不过这有个小问题就是对于1来说有两个结果 123、132,这需要用List来保存结果不过这样实在不够优雅所以我选择了钟爱的 yield return来简化代码。

对于递归程序来说最关键的就是找到终结点, 一开始我试了几个终结条件都不成功,最后冷静下来琢磨了一下一次排序的过程 就是把N个数都枚举了一遍所以终结条件就是数字的位数。就省最后一个问题了排 列中不能有重复的,这个只要模拟一下排序的过程就明白了:

开始:选出 最左边的数字1,其字符串下标为0,当前枚举了1个数

递归第一次:从头 开始遍历,因为上一轮下标为0的数字已经被取了,所以使用下标为1的数字,判 断该下标1是否已经被使用,因为没被使用,那么继续递归,当前枚举了2个数

递归第二次:因为当前枚举的是第3个数所以到达终结点,返回3

在这一次排序过程中我们需要记录每次被选中的数字的下标,再下次枚举时要进 行判断是否已经存在了,所以我使用了一个和数字位数相同大小的数组来记录每 次排序过程中选中的数字的下标。

好了,上面都没看懂也没关系直接上代 码,代码是最好的文档,不过在贴具体代码之前我要下介绍下我的两个辅助函数 :

view plaincopy to clipboardprint?
//将一个操作施加 到每一个遍历出来的元素上 

    public static void For<T>(this IEnumerable<T> itor, Action<T> proc)
    {
      foreach (T item in itor)
         proc(item);
    }

    //判断一个元素是否在 一个数组中
    public static bool Exist<T>(this T[] arr, Func<T, bool> predicate)
    {
      for (int i = 0; i < arr.Length; ++i)
      {
         if (predicate(arr[i]))
          return true;
       }
      return false;
    }

     //ok,核心代码来了:
    public static IEnumerable<string> Combin(string source)
    {
       int[] trace = new int[source.Length];
      for (int i = 0; i < source.Length; ++i)
      {
         foreach (string item in Combin(source, i, 1, trace))
         {
          yield return item;
         }
      }
    }
    /// <summary>
    /// 排序递归算法
    /// </summary>
    /// <param name="source"> 数字</param>
    /// <param name="cur"> 当前下标</param>
    /// <param name="deep">当前枚举个数</param>
    /// <param name="trace">跟踪,用于去重复</param>
    /// <returns>返回排序好的数字</returns>
     private static IEnumerable<string> Combin(string source, int cur, int deep, int[] trace)
    {
      char tmp = source[cur];               //得到当前枚举数字
       trace[deep - 1] = cur;               //将当前下标 放入跟踪中
      if (deep == source.Length)              //终结条件 
        yield return tmp.ToString ();
      else 
      {
        for (int i = 0; i < source.Length; ++i)     //枚举 
         {
          for (int j = deep; j < trace.Length; ++j)  //跟踪清零 
            trace[j] = -1;               //-1代表未作记录 
           if (cur == i || trace.Exist(p =>      //重复过滤 
                        {
                           if (p == -1) return false;
                            return p == i;
                        }))
             continue;
          foreach (string tail in Combin(source, i, deep + 1, trace))
           {
            yield return tmp + tail;
           }
        }
      }
    }
    //看看效果吧 
    public static void Main()
     {
      Combin("1234").For(i => Console.WriteLine(i));
    }
//将一个操作施加到每一个遍历 出来的元素上

    public static void For<T>(this IEnumerable<T> itor, Action<T> proc)
    {
       foreach (T item in itor)
        proc(item);
    }

    //判断一个元素是否在一个数组中
     public static bool Exist<T>(this T[] arr, Func<T, bool> predicate)
    {
      for (int i = 0; i < arr.Length; ++i)
      {
        if (predicate (arr[i]))
          return true;
      }
      return false;
    }

    //ok,核心 代码来了:
    public static IEnumerable<string> Combin (string source)
    {
      int[] trace = new int [source.Length];
      for (int i = 0; i < source.Length; ++i)
      {
        foreach (string item in Combin(source, i, 1, trace))
        {
           yield return item;
        }
      }
    }
    /// <summary>
    /// 排序递归 算法
    /// </summary>
    /// <param name="source">数字</param>
    /// <param name="cur">当前下标</param>
     /// <param name="deep">当前枚举个数</param>
    /// <param name="trace">跟踪,用于去重复 </param>
    /// <returns>返回排序好的数字 </returns>
    private static IEnumerable<string> Combin(string source, int cur, int deep, int[] trace)
    {
      char tmp = source[cur];               //得 到当前枚举数字
      trace[deep - 1] = cur;                //将当前下标放入跟踪中
      if (deep == source.Length)             //终结条件
         yield return tmp.ToString();
      else
       {
        for (int i = 0; i < source.Length; ++i)      //枚举
        {
          for (int j = deep; j < trace.Length; ++j)  //跟踪清零
             trace[j] = -1;               //-1代表未作记录
           if (cur == i || trace.Exist(p =>      //重复 过滤
                        {
                           if (p == -1) return false;
                             return p == i;
                         }))
            continue;
           foreach (string tail in Combin(source, i, deep + 1, trace))
           {
            yield return tmp + tail;
          }
        }
       }
    }
    //看看效果吧
    public static void Main()
    {
      Combin ("1234").For(i => Console.WriteLine(i));
    }

时间: 2024-08-30 13:11:21

N位数排序问题的通用解决方法的相关文章

Win7下游戏全屏问题通用解决方法

  显卡设置问题,推荐2个方法.如果你是n卡直接推荐使用第二种的n卡设置,快捷方便. 一.Windows7下游戏全屏问题通用解决方法(推荐使用): Win键+R键,打开运行窗口,输入regedit 回车,这样就打开了注册表编辑器,然后,定位到以下位置: HKEY_LOCAL_MACHINESYSTEMControlSet001ControlGraphicsDriversConfiguration 在Configuration这上面右键,选择查找,输入Scaling,在右框找到scaling,右键

防止ACCESS数据库被下载的一个通用解决方法

防止ACCESS数据库被下载的一个通用解决方法:在IIS里面Web站点的属性,主目录=>配置=>应用程序影射=>添加随便做一个0字节的dll用来影射mdb文件.明白了吧?dll文件不是可用的ISAPI dll,IIS肯定报错啊..那么无论MDB是什么名字,都不会被下载了.

ruby安装gem包失败的通用解决方法_ruby专题

ruby语言升级还是比较勤快的.但是数量众多的版本使得程序库的兼容性成了大问题.有些gem表示明确不支持某个特定版本以前的ruby,而有些gem则与较高的版本不兼容.再加上gem本身也有版本,简直是乱成了一锅粥.即使使用了rvm.rbenv之类ruby版本管理工具也避免不了掉入坑中.并且时不时的一些其它环境设置也给你捣乱.所以一般使用ruby程序时,对升级ruby版本或各种gem版本都是比较慎重的,避免一时手贱掉入坑中. 当然你也不能因此就做缩头乌龟,某些情况下还是不得不升级的.比如想使用rub

安卓模拟器无法安装“系统opengl版本过低”的通用解决方法

  在安装安卓模拟器时,出现"系统opengl版本过低",下图提示,说明你的显卡暂不支持模拟器: 遇到这个问题,主要是3种原因 1.你的电脑没有显卡 解决方案:这个问题若不换电脑硬件是暂时无解的,只能等待我们模拟器支持集成显卡了 2.你的电脑显卡确实不支持OpenGL2.0 解决方案:这个问题只能通过更换显卡来解决了 3.电脑显卡的驱动不存在或者太旧 解决方案: 下载驱动精灵检测安装显卡驱动 >>点击下载<< 运行驱动精灵,点击"一键体检"安

utf-8 网页不显示+utf-8网页乱码的通用解决方法_应用技巧

在windows操作系统上使用IE作为浏览器时.常常会发生这样的问题:在浏览使用UTF-8编码的网页时,浏览器无法自动侦测(即没有设定"自动选择"编码格式时)该页面所用的编码.即使网页已经声明过编码格式: <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 由此造成某些含有中文UTF-8编码的页面产生空白输出. 如果使用的是Mozilla.Mozi

php $_SERVER[&amp;quot;REQUEST_URI&amp;quot;]获取值的通用解决方法_php技巧

复制代码 代码如下: <?php // 说明:获取 _SERVER['REQUEST_URI'] 值的通用解决方案 function request_uri() { if (isset($_SERVER['REQUEST_URI'])) { $uri = $_SERVER['REQUEST_URI']; } else { if (isset($_SERVER['argv'])) { $uri = $_SERVER['PHP_SELF'] .'?'. $_SERVER['argv'][0]; }

utf-8 网页不显示+utf-8网页乱码的通用解决方法

在windows操作系统上使用IE作为浏览器时.常常会发生这样的问题:在浏览使用UTF-8编码的网页时,浏览器无法自动侦测(即没有设定"自动选择"编码格式时)该页面所用的编码. 即使网页已经声明过编码格式: <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 由此造成某些含有中文UTF-8编码的页面产生空白输出. 如果使用的是Mozilla.Moz

win7玩游戏无法全屏的解决方法

  Windows7是目前使用最广泛的操作系统,如今Windows7操作系统进入到大众生活已经有快两年的时间了,在这期间,各家游戏厂商推出的游戏也全面向Windows7靠拢,但是很多经典的游戏在Windows7下却不能全屏运行,想要解决这个问题,方法有三: 提示:修改注册表操作具备一定风险,请用户慎重操作. 一.Windows7下游戏全屏问题通用解决方法 修改注册表解决游戏全屏显示问题 Win键+R键,打开运行窗口,输入regedit 回车,这样就打开了注册表编辑器,然后,定位到以下位置: HK

Win7系统笔记本不能全屏游戏的解决方法

  在Windows7系统下,人们在使用笔记本玩游戏时有时会发现屏幕居中两边有黑条,如何能让游戏全屏显示呢,下面给大家介绍Windows7游戏全屏问题通用解决方法. Win键+R键,打开运行窗口,输入regedit 回车,这样就打开了注册表编辑器,然后,定位到以下位置: HKEY_LOCAL_MACHINESYSTEMControlSet001ControlGraphicsDriversConfiguration 在Configuration这上面右键,选择查找,输入Scaling,在右框找到s