LeetCode:1187. Make Array Strictly Increasing

在这里插入图片描述

这题还是相当难的,但是给我的启发也很多。
首先先说解法:
从LIS这道题目而来。
LIS的dp方程是:对于j < i,if (nums[j] < nums[i]) , dp[i] = max(dp[i], 1 + dp[j])。
这道题是这样的:
对于j < i, if (nums[j] < nums[i]),我们尝试把j~i之间的所有数字都换成arr2里面的。如果可以的话,设change是需要换的个数,dp[i] = min(dp[i], change+dp[j]).
可能有疑问:为什么要把所有的都换成arr2里面的呢?先看代码,后面解释:

class Solution {
public:
    int makeArrayIncreasing(vector<int>& arr1, vector<int>& arr2) {
        int sz = arr1.size();
        sort(arr2.begin(), arr2.end());
        vector<int> dup{arr2[0]};
        for (int i = 1; i < arr2.size(); ++i)
            if (arr2[i] != arr2[i-1])
                dup.push_back(arr2[i]);
        arr2 = std::move(dup);
        arr1.insert(arr1.begin(), INT_MIN);//因为可能要从第一个开始换,所以最前面加一个
        arr1.push_back(INT_MAX);//最后面是最终情况
        vector<int> dp(sz+2, INT_MAX);//以arr1[i]结尾的最多要换多少次
        dp[0] = 0;
        for (int i = 1; i < sz+2; ++i) {
            for (int j = 0; j < i; ++j) {
                if (arr1[j] < arr1[i] && dp[j] != INT_MAX) {
                    int change = fun(arr1, arr2, j, i);
                    if (change >= 0)
                        dp[i] = min(dp[i], dp[j] + change);
                }
            }
        }
        return dp[sz+1] == INT_MAX ? -1 : dp[sz+1];
    }
private:
    int fun(vector<int>& arr1, vector<int>& arr2, int beg, int end) {
        if (beg+1 == end)
            return 0;
        int idx = binarySearch(arr2, arr1[beg]);
        int requireNum = end-beg-1;
        if (arr2.size()-idx-1 >= requireNum && arr2[idx+requireNum] < arr1[end]) 
            return requireNum;
        else
            return -1;
    }
    
    int binarySearch(vector<int>& nums, int target) {
        int lo = 0, hi = nums.size()-1;
        int mid;
        while (lo <= hi) {
            mid = lo + (hi - lo) / 2;
            if (target < nums[mid])
                hi = mid-1;
            else if (target > nums[mid])
                lo = mid+1;
            else
                return mid;
        }
        return hi;
    }
};

对上面问题的解释,直接上我在评论区的留言吧:
I want to say something confused me at first: why we try to replace all elements in arr1[j+1,i-1] in the check function? If some elements can be used between [j+1, i-1], why we should replace them?
Here is my thought:
we says “some elements can be used” actually means that “there is an index k (i < k < j), arr1[j] < arr1[k] < arr1[i]”,and we don’t want to replace it. But actually even though arr1[j] < arr1[k] < arr1[i], some element arr1[k] must be replaced. For example, arr1=[1, 5, 99, 100, 100]. 99 must be replaced to get the final result. But in other cases, the element arr1[k] can be kept, like arr1 = [1, 5, 10, 100, 100], 10 can be kept. That’s OK, because for (int j = 0; j < i; j++) j will iterate on number 10 and we will get the right answer there.

接下来谈谈这道题目对我的启发:
(面试不一定会问这么难的,但是有了下面的思路面对简单一些的会好想很多)。
(即使问了这么难的,给出思路就很好了,所以思考这类问题还是有意义的)

1.尝试和熟悉的一些经典问题去靠拢。比如这题可以思考LIS。这应该是这道问题最重要的一步。
2.另外,难问题还是由小问题组成的,比如这道题的check函数这么完成算是一个了。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值