LeetCode 77 组合(自用)

题目描述:

        刚学会的回溯(见46题全排列),这里稍作参考,修改一下

    //fin记录当前填入多少数字到了arry
    void BackTrack(vector<int> arry, int k,int fin)
    {
        if(fin==k)
        {
            //注意:这里传入的arry长为n,需要截断
            arry.erase(arry.begin()+k,arry.end());
            
            //填入
            result.push_back(arry);
            return;
        }
        else
        {
            for(int i=fin+1;i<arry.size();i++)//将所有未选元素中依次填入fin处
            {
                swap(arry[fin],arry[i]);//挑一个后面的放到fin处
                BackTrack(arry,k,fin+1);
                swap(arry[fin],arry[i]);//回溯,换回来,准备将下一个元素填入fin
            }
            
        }
    }
    
    vector<vector<int>> result;
    
    vector<vector<int>> combine(int n, int k) 
    {
        vector<int> tmp;
        //传一个[1,n]的数组进去
        for(int i=1;i<n+1;i++)
            tmp.push_back(i);
        BackTrack(tmp,k,0);
        return result;
    }

        那当然结果是不对, 截断之后会认为[1,4] 和 [4,1]是两个排列,但是此题视作一个排列。可以加一个大小的限制,只将比当前vector大的元素加入。

        故做如下修改:

   //给定上界n,每次只将更大的元素加入,取代了上代码tmp
   //max记录target中最大的值,其实就是最后一个元素,为了避免判断target为空的情况,多传个参
    void Select(int n,int k, vector<int> &target,int max)
    {
        if(k==target.size())
        {
            result.push_back(target);
            return;
        }
        else
        {
            //target的范围是[1,max],i需要[max+1,n]
            for(int i=max+1;i<n+1;i++)
            {
                target.push_back(i);
                Select(n,k,target,i);

                //回溯,依次填入下个元素
                target.pop_back();
            }
        }
    }

    vector<vector<int>> combine(int n, int k) 
    {
        vector<int> tmp;
        //一开始tmp为空,max为0
        Select(n,k,tmp,0);
        return result;
    }

        注意::target前面的&对传参的时空优化都很重要!自己体会优化前后:

 

        到这里其实感觉优化到头了, 看看dl的解答,发现了另一个优化点:

        for循环中的 i 其实不一定能取到 n,如:

        给定序列1~7,k=5,只要拿出两个元素即可;这就意味着:序列[1,5]开头的目标序列不存在!因为默认每次加入的元素都比5大,而跳过了2,3,4,这样的序列最长都只有[1,5,6,7],循环应该结束,在此状态下如果让i遍历到7无疑是一种浪费。

        故 i 和n的关系为:

                ①target填充到k个元素,还需 k - target.size()个元素;

                ②当前剩余未填充的元素范围 [ i , n ]  共 n - i +1 个元素;

                ③如果要循环继续,剩余的元素一定要比还需要的元素多,即:

n - i +1\geqslant k - target.size()

                        化简有:

i \leqslant n + 1 - (k - target.size())

        修改判断条件之后表现nice

          (别问为什么内存不优化,问就是空间换时间,绝对不是菜)

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值