Leetcode:Combinations

15 篇文章 0 订阅

1.Problem

Given two integers n and k, return all possible combinations of k numbers out of 1 ... n.

For example,
If n = 4 and k = 2, a solution is:

[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]

2.Pre-Thought

采用01反转法,可解决该问题。(请参考:http://www.360doc.com/content/10/1102/16/4095212_66011065.shtml)

3.Difficulty

3.1Runtime ErrorLast executed input:

出现该问题的原因是未考虑while循环的终止条件,使得迭代器溢出。这是一个很深刻的教训!!!

            // 寻找反转位置
            // !!!谨记:迭代器的值最大为end(),要及时跳出循环
            while(!(pre == 1 && cur == 0))
            {
                pre = cur;
                cur = *it++;
                first++; 
                if(!is_first)
                    first_one++;
                if(cur == 1)
                {
                    one_num++;                   
                    if(!is_first)
                        is_first = true;
                }
                if(it == st.end()) 
                    break;
            }

3.2扫描结束的终止条件


            // 如果first = n,直接退出
            if(first_one != n-k+1)

4.Coding

<pre name="code" class="cpp">#include<iostream>
#include<vector>
using namespace std;

class Solution
{
public:
    vector<vector<int> > combine(int n, int k)
    {
        // 对10集合和结果集合进行初始化
        vector<int> sub_result;
        vector<vector<int> > result;
        vector<int> st(k, 1);
        st.insert(st.end(), n - k, 0);
        int i;
        // 对每一次扫描所需的变量进行声明
        int pre = -1;// 扫描的前一个数
        int cur = -1;// 当前扫描的数
        
        int first = -1;// 记录第一个10的位置,这是10反转的位置
        int first_one = 1;// 记录第一个1的位置
        bool is_first = false;// 判断1是否是第一次出现
        int num = 0;// 输出当前的数
        int k_num = 0;// 记录1的个数
        int one_num = 0;// 记录10组合前面1的个数
        int zero_num = 0;// 记录10组合前面0的个数
        vector<int>::iterator it;
        vector<int>::iterator b;
        vector<int>::iterator e; 

        // 如果k=1,分别输出1,2,.....n即可
        if(k == 1)
        {
            for(i = 1; i <= n; i++)
            {
                sub_result.push_back(i);
                result.push_back(sub_result);
                sub_result.clear();
            }
            return result;
        }
        // 如果n=k,直接输出1,2......n即可
        if(n == k)
        {
            for(i = 1; i <= n; i++)
            {
                sub_result.push_back(i);
            }
            result.push_back(sub_result);
            sub_result.clear();
            return result;
        }
 
        // 初始化状态,输出1,2,3......k
        for(i = 1; i <= k; i++)
        {
            sub_result.push_back(i);
        }
        result.push_back(sub_result);

        do 
        {
            // 对每一次内层循环进行初始化
            sub_result.clear();
            pre = -1; 
            it = st.begin();
            cur = *it++;// 从第一个数开始扫描
            first = 0;
            first_one = 1;
            is_first = false;
            one_num = 0;
            zero_num = 0;
            if(cur == 1)
            {
                one_num = 1;
                first_one = 1;
                is_first = true;
            }
            
            // 寻找反转位置
            // !!!谨记:迭代器的值最大为end(),要及时跳出循环
            while(!(pre == 1 && cur == 0))
            {
                pre = cur;
                cur = *it++;
                first++; 
                if(!is_first)
                    first_one++;
                if(cur == 1)
                {
                    one_num++;                   
                    if(!is_first)
                        is_first = true;
                }
                if(it == st.end()) 
                    break;
            }
          
            // 如果first = n,直接退出
            if(first_one != n-k+1)
            {
                // 反转
                *(it - 1) = 1;
                *(it - 2) = 0;

                // 将10组合前面的1全部置前
                one_num--;// 01组合前面1的个数
                zero_num = first - one_num - 1;// 01组合前面0的个数
                b = st.begin();
                e = it - 2;
                st.erase(b, e);// 先删除10组合前面的所有数
                b = st.begin();
                st.insert(b, zero_num, 0);// 在10组合前面先插入zero_num个0
                b = st.begin();// 记得每一次更新首元素时,要更新迭代器
                st.insert(b, one_num, 1);// 在10组合前面再插入one_num个1

                // 对10元素集合进行遍历,将1所在位置的数存入sub_result集合中
                it = st.begin();
                num = 0;
                k_num = 0;
                while(k_num != k)
                {
                    num++;
                    if(*it++ == 1)
                    {
                        k_num++;
                        sub_result.push_back(num);
                    }
                }
                result.push_back(sub_result);
            }
        }while(first_one != n-k+1);
        return result;
    }
};

int main()
{
    int n = 4;
    int k = 2;
    vector<vector<int> > result;
    Solution sol;
    result = sol.combine(n, k);
    vector<vector<int> >::iterator it1 = result.begin();
    
    while(it1 != result.end())
    {
        vector<int> temp = *it1++;
        vector<int>::iterator it2 = temp.begin();
        while(it2 != temp.end())
        {
            cout<<*it2++<<" ";
        }
        cout<<"Lenght:"<<temp.size()<<endl;
    }
    cout<<"Result:"<<result.size()<<endl;
    return 0;
}


 
       




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值