二分dp

二分dp

二分dp

目前仅发现求解数组最长递增子序列可以用这个,dp[i]表示子序列长度为i+1时结尾的数字。
例题,求数组中最长的严格递增子序列。题目传送门

二分DP进阶版(困难题)

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        vector<int>dp;    //dp[i]表示长度为i的递增子序列结尾的数字
        dp.push_back(INT_MAX);
        for(auto num : nums){
            int left = 0,right = dp.size()-1;
            while(left<=right){
                int mid = (left+right)/2;
                if(num<=dp[mid]){
                    right = mid-1;
                }else{
                    left = mid+1;
                }
            }
            if(left == dp.size()){
                dp.push_back(num);
            }else{
                dp[left] = num;
            }
            //cout<<num<<" "<<left<<" "<<dp.size()<<endl;
        }
        return dp.size();       
    }
};

解题思路:
每次二分实际上是找出dp数组中比num大于等于的数中最小的那个数的下标,那么自动 return left。

这个二分在c++自带函数库中对应为lower_bound,即第一个大于目标值的下标,返回的是迭代器,实现代码如下:

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        vector<int>dp;    //dp[i]表示长度为i的递增子序列结尾的数字
        for(auto num : nums){
            int left = 0,right = dp.size()-1;
            left = lower_bound(dp.begin(),dp.end(),num)-dp.begin();
            if(left == dp.size()){
                dp.push_back(num);
            }else{
                dp[left] = num;
            }
            //cout<<num<<" "<<left<<" "<<dp.size()<<endl;
        }
        return dp.size();       
    }
};

#进阶困难版
困难题

这里是引用

小tip: 每一次操作使数组中的一个数字改变为任意数,那么是一个数组变为严格递增即为数组长度减去最大递增子数组的长度。

class Solution {
public:
    template<typename T>

    int lis(vector<T> a) {
        vector<T> dp;
        for(auto& x : a) {
            auto it = upper_bound(dp.begin(), dp.end(), x); 

        //因为只要求最长不下降子序列,所以用upper求得大于的那个,然后更改
        //         最长递增子序列用lower

            if(it == dp.end()) dp.push_back(x);  //如果找不打比x大的元素,那么将其加进去
            else *it = x;  //找到的话,对其进行修改
        }
        return dp.size();
    }
    int kIncreasing(vector<int>& a, int k) {
        int n = a.size();
        int ans = 0;
        for(int i = 0; i < k; ++i) {
            vector<int> b;
            for(int j = i; j < n; j += k) {
                b.push_back(a[j]);
            }
            ans += lis(b);
        }
        return n - ans;
    }
};

作者:elegant-kapitsaexi
链接:https://leetcode-cn.com/problems/minimum-operations-to-make-the-array-k-increasing/solution/fen-zu-lis-by-elegant-kapitsaexi-prmn/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值