IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> LeetCode 一周总结 -> 正文阅读

[数据结构与算法]LeetCode 一周总结

673. 最长递增子序列的个数

题目:给定一个未排序的整数数组,找到最长递增子序列的个数。

方法一:动态规划。

考虑前i个元素,令 d p [ i ] dp[i] dp[i]为以第 i i i个元素为结尾的最长递增子序列的长度,令 c n t [ i ] cnt[i] cnt[i]表示以第 i i i个元素为结尾的最长递增子序列的个数,这里nums[i]必须被选取

则有转移方程:
d p [ i ] = m a x ( d p [ j ] ) + 1 , 其 中 0 ≤ j < i , 且 n u m s [ j ] < n u m s [ i ] dp[i]=max(dp[j])+1,其中0≤j<i,且nums[j]<nums[i] dp[i]=max(dp[j])+1,0j<inums[j]<nums[i]

c n t [ i ] cnt[i] cnt[i]为所有满足 d p [ j ] + 1 = d p [ i ] dp[j]+1=dp[i] dp[j]+1=dp[i] 0 ≤ j < i 0≤j<i 0j<i c n t [ j ] cnt[j] cnt[j]的和。

最后,数组的最长递增子序列的长度 m a x l e n = m a x ( d p [ i ] ) , 其 中 0 ≤ i < n maxlen=max(dp[i]),其中0≤i<n maxlen=max(dp[i])0i<n
最长递增子序列的个数为 r e s u l t = ∑ ( c n t [ i ] ) result=\sum(cnt[i]) result=(cnt[i]),对于那些 i i i满足 d p [ i ] = L dp[i]=L dp[i]=L

代码:

int findNumberOfLIS(vector<int>& nums) {
        int n=nums.size();
        if(n==0) return 0;
        if(n==1) return 1;
        vector<int> dp(n);
        vector<int> cnt(n);
        dp[0]=1;
        cnt[0]=1;
        for(int i=1;i<n;i++)
        {
            cnt[i]=0;
            int max=0;
            for(int j=0;j<i;j++)
            {
                if(nums[i]>nums[j])
                {
                    if(dp[j]>max) max=dp[j];
                }
            }
            dp[i]=max+1;
            if(dp[i]==1) cnt[i]=1;
            else
            {
                for(int j=0;j<i;j++)
                {
                    if(nums[i]>nums[j] && dp[j]==max)
                    {
                    cnt[i]+=cnt[j];
                    }
                }
            }
        }
        int maxlen=0;
        int result=0;
        for(int i=0;i<n;i++)
        {
            if(dp[i]>maxlen) maxlen=dp[i];
        }
        for(int i=0;i<n;i++)
        {
            if(dp[i]==maxlen)
            {
                result+=cnt[i];
            }
        }
        return result;
    }

方法二:贪心算法+二分查找

(1)仅求最长递增序列长度:
想要递增的序列尽可能长,希望末位加上的数越小越好。令 d [ i ] d[i] d[i]为长度为 i i i的递增序列的末位元素的最小值,用 l e n len len表示目前最长递增序列的长度, l e n len len的起始值为1, d [ 1 ] = n u m [ 0 ] d[1]=num[0] d[1]=num[0];

证明,序列 d d d是关于 i i i是递增的。若 d [ j ] > d [ i ] d[j]>d[i] d[j]>d[i] j < i j<i j<i,则我们考虑从长度为 i i i的递增数列中删掉最后 i ? j i-j i?j个数,可知长度为 i i i的序列的第 j j j个数小于 d [ i ] d[i] d[i],从而小于 d [ j ] d[j] d[j],由序列 d d d的定义可知矛盾。

遍历 n u m num num,更新 d d d l e n len len,若 n u m [ i ] > d [ l e n ] num[i]>d[len] num[i]d[len],则 l e n = l e n + 1 len=len+1 len=len+1,否则,在 d [ 1 , 2 , . . . , l e n ] d[1,2,...,len] d[1,2,...,len]中找到 i i i,满足 d [ i ? 1 ] < n u m [ j ] < d [ i ] d[i-1]<num[j]<d[i] d[i?1]<num[j]<d[i],令 d [ i ] = n u m [ j ] d[i]=num[j] d[i]=num[j].根据 d d d的单调性,通过二分法查找合适的 i i i,优化时间复杂度。

总结:
对于 n u m s nums nums,按如下方法更新:
设当前已求出的最长上升子序列的长度为 len \textit{len} len(初始时为 1),从前往后遍历数组 nums \textit{nums} nums,在遍历到 nums [ i ] \textit{nums}[i] nums[i]时:

如果 nums [ i ] \textit{nums}[i] nums[i] > d [ len ] d[\textit{len}] d[len] ,则直接加入到 d d d 数组末尾,并更新 len = len + 1 \textit{len} = \textit{len} + 1 len=len+1

否则,在 d d d 数组中二分查找,找到第一个比 nums [ i ] \textit{nums}[i] nums[i]小的数 d [ k ] d[k] d[k] ,并更新 d [ k + 1 ] = nums [ i ] d[k + 1] = \textit{nums}[i] d[k+1]=nums[i]

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int len = 1, n = (int)nums.size();
        if (n == 0) {
            return 0;
        }
        vector<int> d(n + 1, 0);
        d[len] = nums[0];
        for (int i = 1; i < n; ++i) {
            if (nums[i] > d[len]) {
                d[++len] = nums[i];
            } else {
                int l = 1, r = len, pos = 0; // 如果找不到说明所有的数都比 nums[i] 大,此时要更新 d[1],所以这里将 pos 设为 0
                while (l <= r) {
                    int mid = (l + r) >> 1;
                    if (d[mid] < nums[i]) {
                        pos = mid;
                        l = mid + 1;
                    } else {
                        r = mid - 1;
                    }
                }
                d[pos + 1] = nums[i];
            }
        }
        return len;
    }
};


  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-10-03 17:18:25  更:2021-10-03 17:20:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 4:29:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码