• C#获取数组/字符串的k个字符的全部组合


       static IEnumerable<string> foo(string metachars, int i)
            {
                var query = metachars.Select(x => x.ToString().AsEnumerable());
                while (query.First().Count() < i)
                {
                    var ee = query.First();
                    //是原始的
                    //query = query.SelectMany(x => metachars.Where(y => y > x.Last()).Select(y => x.Concat(y.ToString().AsEnumerable())));
    
                    query = query.SelectMany(x => metachars.Where((y, y_index) => y_index > metachars.IndexOf(x.Last())).Select(y => x.Concat(y.ToString().AsEnumerable())));
                    
    
                    //无论哪种写法,都无法应用于内部含有重复字符串,因为对于上方的,char相同,会忽略掉重复的那个;下方那个返回第一个index,会出现重复
                }
                    
                return query.Select(x => string.Join(",", x));
            }
             foreach (var item in foo("bacdef", 4))//使用
                {
                    Console.WriteLine(item);
                }

     第一行按照char大小来排的是网络大神写的

    第二行按照索引是我改进的另一种写法

     对于为什么要加AsEnumerable(),是因为只有可遍历的迭代器,才可以使用Concat方法

    上方公式的原理就是:

     首先第一次,query可迭代的每个里面只含有一个字符,无论取First()还是第二、第三个,他们的容量count都是1

    然后向后找,就是我们基本for循环来做的思想,一个个向后,如:abcd这样我们就是ab ac ad bc bd cd 这样一个个固定前方索引,向后找。此次count都是2

    若输入为"abcd",3的话

    第一次循环后query变为:ab ac ad bc bd cd

    第二次过程则为:ab,因为b的索引为1,依次找比b大的,则abc abd, 对于ac ad..也是这样,对于cd,找比d大的没有,则就找不到啦

    他的整个思想为,我要取数组的k个值的全部组合,那么我一点点从取一个开始(当然就是本身),然后所有取2个的组合,然后在2个的基础上取所有3个的组合,以此类推,直到k个!

    对于数组也是一样,只需要在Last()后加.ToString(),对于int类型数组,也是只需要将Last()后转为int类型即可

       static IEnumerable<string> foo2(List<string> metachars, int i)
            {
                var query = metachars.Select(x => x.ToString().AsEnumerable());
                while (query.First().Count() < i)
                {
                    var ee = query.First();
                    //是原始的
                    //query = query.SelectMany(x => metachars.Where(y => y > x.Last()).Select(y => x.Concat(y.ToString().AsEnumerable())));
    
                    query = query.SelectMany(x => metachars.Where((y, y_index) => y_index > metachars.IndexOf(x.Last().ToString())).Select(y => x.Concat(y.ToString().AsEnumerable())));
    
                    //无论哪种写法,都无法应用于内部含有重复字符串,因为对于上方的,char相同,会忽略掉重复的那个;下方那个返回第一个index,会出现重复
                }
    
                return query.Select(x => string.Join(",", x));
            }
            List<string> list2 = new List<string>() { "a","b","c","d","e","f"};//使用
    
                foreach (var item in foo2(list2, 3))
                {
                    Console.WriteLine(item);
                }

    如果想要int的话,就先使用string,然后再转成int

     使用List

     public static List<string> getAllCombination(int k, List<int> list)
            {
                var query = list.Select(x => x.ToString().AsEnumerable());
                while (query.First().Count() < k)
                {
                    query = query.SelectMany(x => list.Where((y, y_index) => y_index >list.FindIndex(z=>z==int.Parse(x.Last().ToString()))).Select(y=>x.Concat(y.ToString())));
                }
                return query.Select(x => string.Join(",", x)).ToList();
            }

     以上的代码,看似没啥问题,但是当我数组中含有2位以上的数的时候,那就完蛋了,全乱套了,为了解决这个问题,我研究出如下方法!

    通用非重复数组取数字方法!!!!By 程序杰杰

    //适用于所有的非重复的数组方法!!! 

    //由博主本人研究写出,如需引用必须注明博主网址哦

      public static List<List<int>> getAllCombinationCeshi2(int k, List<int> list)
            {
                List<List<int>> list1 = new List<List<int>>();//用来记录,选取k个元素的全部组合
                list.ForEach(x => { list1.Add(new List<int>() { x }); });
    
                List<string> listCopy = new List<string>();
                list.ForEach(x=> listCopy.Add(x.ToString()));
                while (list1[0].Count < k)
                {
                    List<List<int>> list2 = new List<List<int>>();
                    //select内部只能是一个个的,将这些组合成一个序列
                    //selectMany内部必须要是可迭代的序列,将序列合并
                    //选择比当前索引大的全部组合
                    listCopy = listCopy.SelectMany((x,x_index)=> list.Where((y, y_index) => y_index > list.FindIndex(z => z == list1[x_index][list1[x_index].Count-1])).Select(y=> x+","+y)).ToList();
                    //更新list1
                    foreach (var item in listCopy)
                    {
                        list2.Add(new List<int>());//此时一定是最后的一个list,因为是新加的嘛
                        string[] strs=item.Split(',');
                        foreach (var item1 in strs)
                        {
                            list2[list2.Count - 1].Add(int.Parse(item1));
                        }
    
                    }
                    list1 = list2;
                }
                return list1;
    
            }

    Select与SelectMany

            //测试
                List<int> listCeshi = new List<int>() { 10,2,30,4,5};
                IEnumerable<int> ceshi01 = listCeshi.Select(x=>x);//select内部lambda是一个个的值,将这些值合并为一个新的序列
                IEnumerable<int> ceshi02 = listCeshi.SelectMany(x => listCeshi.Select(y => y));//selectMany内部lambda是一个序列,它将序列合并为一个序列

    =====2020=====

    java实现

    //随机取字符串k个的全部排列(目前写字符无重复)
    public class RandomFetchChar {
        public static void main(String[] args) {
            //System.out.println("abv".substring(3,3));
            System.out.println(getAllPermutation("abc",4));
    
        }
        static String front="";
        static String rear="";
        static ArrayList<String> temp=null;
        public static ArrayList<String> getAllPermutation(String str, int k){
            if(str.length()<k){
                System.out.println("输入有误");
                return null;
            }
            ArrayList<String> res=new ArrayList<String>();
            if(k==1){
                for (int i = 0; i < str.length(); i++) {
                    res.add(""+str.charAt(i));
                }
            }else {
                for (int i = 0; i < str.length(); i++) {
                    front=str.substring(0,i);
                    rear=str.substring(i+1,str.length());
                    temp=getAllPermutation(front+rear,k-1);
                    for (int j = 0; j < temp.size(); j++) {
                        temp.set(j,str.charAt(i)+temp.get(j));
                    }
                    res.addAll(temp);
    
                }
            }
            return res;
        }
    }

     //泛型数组实现

     private <T> LinkedList<LinkedList<T>> getKCombine(T arr[],int k){
            LinkedList<T> linkedList=new LinkedList<>();
            for (int i = 0; i < arr.length; i++) {
                linkedList.add(arr[i]);
            }
            LinkedList<LinkedList<T>> assistList=new LinkedList<>();
            LinkedList<LinkedList<T>> res=getAllCombine(linkedList,arr.length,k,assistList);
            return res;
        }
    
        private <T> LinkedList<LinkedList<T>> getAllCombine(LinkedList<T> linkedList,int len,int k,LinkedList<LinkedList<T>> assistList){
            if(len<k){
                throw new RuntimeException("k值输入过大");
            }
            LinkedList<LinkedList<T>> res=new LinkedList<>();
            LinkedList<T> temp;
            if(k==1){
                for (int i = 0; i < linkedList.size(); i++) {
                    temp=new LinkedList<>();
                    temp.add(linkedList.get(i));
                    res.add(temp);
                }
                return res;
            }
            for (int i = 0; i < linkedList.size(); i++) {
                T first=linkedList.get(i);
                linkedList.remove(i);//移除
                assistList=getAllCombine(linkedList,len-1,k-1,assistList);
                linkedList.add(i,first);//执行完再加回来
                for(LinkedList<T> item:assistList){
                    item.addFirst(first);
                }
                res.addAll(assistList);
            }
            return res;
        }
  • 相关阅读:
    文化课随笔
    微积分与无穷级数
    [康复计划]-数论基础
    [Codeforces]CF742(Div.2)A-E
    第一次个人编程作业的过程和想法
    第一次个人编程作业
    Python命令行参数及文件读出写入
    第一次个人编程作业
    第一次个人编程作业
    第一次博客作业
  • 原文地址:https://www.cnblogs.com/ningxinjie/p/12849033.html
Copyright © 2020-2023  润新知