Leetcode 300. 最长递增子序列 记忆化搜索、贪心二分 C++实现

Leetcode 300. 最长递增子序列

问题:给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

算法1:记忆化搜索

        创建一维数组 memo 并赋初始值为 0 ,表示没有被计算过。

        进入 dfs 函数。从后往前递归,如果满足前面字母比后面字母小,那么进行下一层递归(向前)更新 memo 。

        在函数的最后返回值时,要重新遍历递归的原因是:函数 dfs 传入的参数是子序列末尾数字的位置,末尾数字已经定了,所以要遍历一遍。

代码:

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int n = nums.size();
        if(n == 0)  return 0;
        vector<int> memo(n);
        auto dfs = [&](auto &&dfs,int i){
            int &res = memo[i];
            if(res) return res;// 被计算过
            for(int j = 0;j < i;j++)
                if(nums[j] < nums[i])   res = max(dfs(dfs,j),res);
            return ++res;
        };
        int ans = 0;
        for(int i = 0;i < n;i++)  ans = max(ans,dfs(dfs,i));
        return ans;
    }
};

算法2:1:1翻译成递推

代码:

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int n = nums.size();
        if(n == 0)  return 0;
        vector<int> memo(n);
        for(int i = 0;i < n;i++){
            memo[i] = 0;
            for(int j = 0;j < i;j++)
                if(nums[j] < nums[i])   memo[i] = max(memo[i],memo[j]);
            memo[i]++;
        }
        return ranges::max(memo);
    }
};

算法3:贪心 + 二分查找

        遍历 nums 数组,使用二分查找方法找到在 g 数组中,所遍历到的元素应该存放的位置,利用 lower_bound( ) 函数。如果在 g 数组的中间找到应该存放的位置,就替换掉这个元素(注意是替换不是插入)。替换掉这个元素后,数组 g 的长度保持不变,除非后续遍历能够完全覆盖数组 g 后面的数字,也就是记录了之前最长子序列长度。

lower_bound( ) : 返回指向第一个值不小于 val 的位置,也就是返回第一个大于等于 val 值的位置。(通过二分查找)。

        

代码:

class Solution {
public:
    int lengthOfLIS(vector<int> &nums) {
        vector<int> g;
        for (int x : nums){// 遍历nums数组
            auto it = ranges::lower_bound(g, x);//在g中找到可以插入x的位置。前提是有序的情况下
            if (it == g.end())  g.push_back(x); // 如果这个位置在末尾,则添加到g的尾部
            else    *it = x;//否则替换掉那个位置的元素
        }
        return g.size();
    }
};

算法4:原地修改

        在 算法3 的基础上,取消数组 g 的使用,改为原地修改,即在遍历 nums 数组的过程中,如果符合条件,则将其填入对应位置,按照上一方法的思路,如果是在数组最后添加元素,则填完元素后让 end 指针向后移动一位。

代码:

class Solution {
public:
    int lengthOfLIS(vector<int> &nums) {
        auto end = nums.begin();
        for (int x : nums){
            auto it = lower_bound(nums.begin(), end, x);
            *it = x;
            if (it == end)  end++;
        }
        return end - nums.begin();
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值