从n个元素中选择k个的所有组合(包含重复元素)

LeetCode:Combinations这篇博客中给出了不包含重复元素求组合的5种解法。我们在这些解法的基础上修改以支持包含重复元素的情况。对于这种情况,首先肯定要对数组排序,以下不再强调


修改算法1:按照求包含重复元素集合子集的方法LeetCode:Subsets
II
算法1的解释,我们知道:若当前处理的元素如果在前面出现过m次,那么只有当前组合中包含m个该元素时,才把当前元素加入组合

?





1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

class
Solution {

public:

    void
combine(vector<int> &vec, int
k) {

        if(k > vec.size())return;

        sort(vec.begin(), vec.end());

        vector<int>tmpres;

        helper(vec, 0, k, 0, tmpres);

    }

    

    //从vec的[start,vec.size()-1]范围内选取k个数,tmpres是当前组合

    //times是上一个元素出现的次数

    void
helper(vector<int> &vec, int
start, int
k, int
times, vector<int> &tmpres)

    {

        if(vec.size()-start < k)return;

        if(k == 0)

        {

            for(int
i = 0; i < tmpres.size(); i++)

                cout<<tmpres[i]<<" ";

            cout<<endl;

            return;

        }

        if(start == 0 || vec[start] != vec[start-1])//当前元素前面没有出现过

        {

            //选择vec[start]

            tmpres.push_back(vec[start]);

            helper(vec, start+1, k-1, 1, tmpres);

            tmpres.pop_back();

            //不选择vec[start]

            helper(vec, start+1, k, 1, tmpres);

        }

        else//当前元素前面出现过

        {

            if(tmpres.size() >= times && tmpres[tmpres.size()-times] == vec[start])

            {

                //只有当tmpres中包含times个vec[start]时,才选择vec[start]

                tmpres.push_back(vec[start]);

                helper(vec, start+1, k-1, times+1, tmpres);

                tmpres.pop_back();

            }

            helper(vec, start+1, k, times+1, tmpres);

        }

    }

};

从[1,2,2,3,3,4,5]中选3个的结果如下:


修改算法2:同理,可以得到代码如下                   
本文地址

?





1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

class
Solution {

public:

    void
combine(vector<int> &vec, int
k) {

        if(k > vec.size())return;

        sort(vec.begin(), vec.end());

        vector<int>tmpres;

        helper(vec, 0, k, 0, tmpres);

    }

    

    //从vec的[start,vec.size()-1]范围内选取k个数,tmpres是当前组合

    //times是上一个元素出现的次数

    void
helper(vector<int> &vec, int
start, int
k, int
times, vector<int> &tmpres)

    {

        if(vec.size()-start < k)return;

        if(k == 0)

        {

            for(int
i = 0; i < tmpres.size(); i++)

                cout<<tmpres[i]<<" ";

            cout<<endl;

            return;

        }

        for(int
i = start; i <= vec.size()-k; i++)

        {

            if(i == 0 || vec[i] != vec[i-1])//当前元素前面没有出现过

            {

                times = 1;

                //选择vec[i]

                tmpres.push_back(vec[i]);

                helper(vec, i+1, k-1, 1, tmpres);

                tmpres.pop_back();

            }

            else//当前元素前面出现过

            {

                times++;

                //vec[i]前面已经出现过times-1次

                if(tmpres.size() >= times-1 && tmpres[tmpres.size()-times+1] == vec[i])

                {

                    //只有当tmpres中包含times-1个vec[i]时,才选择vec[i]

                    tmpres.push_back(vec[i]);

                    helper(vec, i+1, k-1, times, tmpres);

                    tmpres.pop_back();

                }

            }

        }

    }

};


修改算法3:算法3是根据LeetCode:Subsets
算法2修改未来,同理我们也修改LeetCode:SubsetsII
算法2

?





1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

class
Solution {

public:

    void
combine(vector<int> &vec, int
k) {

        if(k > vec.size())return;

        sort(vec.begin(), vec.end());

        vector<vector<int> > res(1);//开始加入一个空集

        int
last = vec[0], opResNum = 1;//上一个数字、即将要进行操作的子集数量

        for(int
i = 0; i < vec.size(); ++i)

        {

            if(vec[i] != last)

            {

                last = vec[i];

                opResNum = res.size();

            }

            //如果有重复数字,即将操作的子集的数目和上次相同

            int
resSize = res.size();

            for(int
j = resSize-1; j >= resSize - opResNum; j--)

            {

                res.push_back(res[j]);

                res.back().push_back(vec[i]);

                if(res.back().size() == k)//找到一个大小为k的组合

                {

                    for(int
i = 0; i < res.back().size(); i++)

                        cout<<res.back()[i]<<" ";

                    cout<<endl;

                }

            }

        }

    }

};


对于算法4和算法5,都是基于二进制思想,这种解法不适用与包含重复元素的情况

【版权声明】转载请注明出处:http://www.cnblogs.com/TenosDoIt/p/3695463.html

从n个元素中选择k个的所有组合(包含重复元素),布布扣,bubuko.com

时间: 2024-10-24 01:45:54

从n个元素中选择k个的所有组合(包含重复元素)的相关文章

【算法30】从数组中选择k组长度为m的子数组,要求其和最小

原题链接:codeforce 267 Div2 C 问题描述: 给定长度为n的数组a[],从中选择k个长度为m的子数组,要求和最大. 形式描述为:选择$k$个子数组[$l_1$, $r_1$], [$l_2$, $r_2$], ..., [$l_k$l1, $r_k$] (1 ≤ $l_1$ ≤$r_1$ ≤$l_2$ ≤ $r_2$ ≤... ≤$l_k$ ≤ $r_k$ ≤ n; $r_i-r_i+1$), 使得$\sum_{i=1}^{k}\sum_{j=l_i}^{r_i}p_j$ 问题

JS 验证数组中是否包含重复元素

验证JS中是否包含重复元素,有重复返回true:否则返回false function isRepeat(data) { var hash = {}; for (var i in data) { if (hash[data[i]]) { return true; } // 不存在该元素,则赋值为true,可以赋任意值,相应的修改if判断条件即可 hash[data[i]] = true; } return false; }

【LeetCode-面试算法经典-Java实现】【219-Contains Duplicate II(包含重复元素II)】

[219-Contains Duplicate II(包含重复元素II)] [LeetCode-面试算法经典-Java实现][所有题目目录索引] 代码下载[https://github.com/Wang-Jun-Chao] 原题 Given an array of integers and an integer k, find out whether there are two distinct indices i and j in the array such that nums[i] = n

【LeetCode-面试算法经典-Java实现】【217-Contains Duplicate(包含重复元素)】

[217-Contains Duplicate(包含重复元素)] [LeetCode-面试算法经典-Java实现][所有题目目录索引] 代码下载[https://github.com/Wang-Jun-Chao] 原题 Given an array of integers, find if the array contains any duplicates. Your function should return true if any value appears at least twice

leetcode-219-Contains Duplicate II(使用set来判断长度为k+1的闭区间中有没有重复元素)

题目描述: Given an array of integers and an integer k, find out whether there are two distinct indices i and j in the array such that nums[i] = nums[j] and the absolute difference between i and j is at most k. Example 1: Input: [1,2,3,1], k = 3 Output: t

哈希(6) - 判断数组中是否存在重复元素且距离在K之内

给定一个包含多个重复元素的未排序的数组.另外给定一个数字k,且k小于数组大小.判断数组中是否包含重复元素,且它们相隔的距离处于范围k之内. 例如: Input: k = 3, arr[] = {1, 2, 3, 4, 1, 2, 3, 4} Output: false 所有重复元素的距离>k. Input: k = 3, arr[] = {1, 2, 3, 1, 4, 5} Output: true 存在重复元素1,且距离为3(==k). Input: k = 3, arr[] = {1, 2,

JS中选择DOM元素的方法集锦

各种选取元素的方法的速度,用原生的方法比jQuery要快差不多8倍,IE8是最慢的,IE9的速度差不多是IE8的3倍,Chrome的表现最好,其次是Firefox 选取文档元素的方法: 1.通过ID选取元素(getElementById)   1)使用方法:document.getElementById("domId")        其中,domId为要选取元素的id属性值   2)兼容性:低于IE8版本的IE浏览器对getElementById方法的实现是不区分元素ID号的大小写的

Windows Store App 全球化:在XAML元素中引用字符串资源

在应用程序中可以通过XAML元素和后台代码两种方式引用资源文件中的字符串资源.本小节先讲述如何在XAML元素中引用字符串资源的相关知识点. 在XAML元素中可以通过使用x:Uid属性来引用资源文件中的字符串资源,这些字符串资源存储在资源文件中,下面介绍如何在项目中新建资源文件.添加字符串资源以及在XAML元素中通过x:Uid属性引用资源文件中的字符串资源. 在Visual Studio 2012中新建一个Windows应用商店的空白应用程序项目,并命名为StringResourcesInXaml

leetcode | Median of Two Sorted Arrays 寻找2个有序数组中第k大的值

问题 Median of Two Sorted Arrays There are two sorted arrays A and B of size m and n respectively. Find the median of the two sorted arrays. The overall run time complexity should be O(log(m + n)). 分析 本题更经典通用的描述方式时: 给定2个有序数组,找出2个数组中所有元素中第k大的元素. 思路1 直观思