【LeetCode 2111】Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务

106 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务活动详情

一、题目描述

给定一个数组,可以任意修改数组,使其变成一个 k 递增的数组,就是i,i+k,i+k+k这一串要是递增的。求最小操作次数。

数据范围

十万

二、思路分析

显然的一个事实是,可以把这个数组看成n个数组单独求解,因为它们之间没有任何关系。

问题也就转变成了,给定一个数组,求最小操作次数,将它变成不严格递增的数组。

怎么做呢?因为它要求的是不严格递增,也就是不下降,所以我们可以直接找出它最长的不下降子序列,这个就是最优的解,修改其他的即可(让不符合的元素变成和它旁边的一样)。

但是这仅局限于这道题,如果改成要严格递增的话,我们就会遇到新的问题,元素直接可能没有足够的空间去容纳我们修改,也就是直接找出最长不下降子序列并不能解决问题。这个问题我们暂时留着。

如何求最长不下降子序列呢? 这是一个经典的问题,有很多做法,最快的就是二分查找了。

三、AC代码

class Solution {
public:
    int js(vector<int>& q){
        int n = q.size();
        vector<int > lis;
        lis.push_back(999999999);
        for (int i=0; i<n; i++) {
            int p = upper_bound(lis.begin(), lis.end(), q[i]) - lis.begin();
            if (p == lis.size()) lis.push_back(q[i]);
            else lis[p] = q[i];
        }
        return n-lis.size();
    }

    int kIncreasing(vector<int>& arr, int k) {
        int ans=0;
        int n = arr.size();
        for (int i=0; i<k; i++) {
            int p=i;
            vector<int > q;
            while (p < n){
                q.push_back(arr[p]);
                p += k;
            }
            ans += js(q);
        }
        return ans;
    }
};

四、总结

一开始卡在了如何修改才能使得它不下降,后来才发现,正是因为它不下降(不严格递增),使得我们可以很容易地去处理那些不符合的元素,也就使得我们可以粗暴地找出最长不下降子序列就可以了。