【日常系列】LeetCode《29·动态规划4》

news2024/12/29 18:41:40

数据规模->时间复杂度

<=10^4 😮(n^2)
<=10^7:o(nlogn)
<=10^8:o(n)
10^8<=:o(logn),o(1)

内容

字符串/数组dp问题
动态规划中的双状态问题

lc 139【top100】:单词拆分
https://leetcode.cn/problems/word-break/
提示:
1 <= s.length <= 300
1 <= wordDict.length <= 1000
1 <= wordDict[i].length <= 20
s 和 wordDict[i] 仅有小写英文字母组成
wordDict 中的所有字符串 互不相同

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#方案一:dfs1+记忆化
class Solution:
    def wordBreak(self, s: str, wordDict: List[str]) -> bool:
        word_dict=set(wordDict)
        memo={}
        #
        def dfs(i):
            if i==len(s):return True #[5,6),''空字符串 
            if i in memo:return memo[i]
            #
            for end in range(i+1,len(s)+1):
                if s[i:end] not in word_dict:continue #剪枝
                if dfs(end):
                    memo[i]=True
                    return True
            memo[i]=False
            return False
        #
        return dfs(0)

#方案二:dp1
class Solution:
    def wordBreak(self, s: str, wordDict: List[str]) -> bool:
        word_dict=set(wordDict)
        #dp[i] 表示以第 i 个字符开头的子串是否可以被空格拆分成字典中出现的单词
        dp=[False]*(len(s)+1)
        dp[len(s)]=True #表示''
        #如果s[i, j)存在于字典中,且dp[j] == true  那么 dp[i] = true
        for i in range(len(s)-1,-1,-1):#转移方向1
            for j in range(i+1,len(s)+1):
                if s[i:j] not in word_dict:continue
                if dp[j]:dp[i]=True
        return dp[0]

#方案三:dfs2+记忆化
class Solution:
    def wordBreak(self, s: str, wordDict: List[str]) -> bool:
        word_dict=set(wordDict)
        memo={}
        #
        def dfs(i):
            if i==0:return True #[0,1) 取不到以[:0)结尾
            if i in memo:return memo[i]
            #
            for start in range(i-1,-1,-1):
                if s[start:i] not in word_dict:continue #剪枝
                if dfs(start):#分支
                    memo[i]=True
                    return True
            memo[i]=False
            return False
        #
        return dfs(len(s))

#方案三:dp2
class Solution:
    def wordBreak(self, s: str, wordDict: List[str]) -> bool:
        word_dict=set(wordDict)
        dp=[False]*(len(s)+1)
        dp[0]=True#''空字符串
        for i in range(1,len(s)+1):#转移方向2
            for j in range(i-1,-1,-1):
                if s[j:i] not in word_dict:continue
                if dp[j]:
                    dp[i]=True
        return dp[len(s)]       

lc 140:单词拆分 II
https://leetcode.cn/problems/word-break-ii/
提示:
1 <= s.length <= 20
1 <= wordDict.length <= 1000
1 <= wordDict[i].length <= 10
s 和 wordDict[i] 仅有小写英文字母组成
wordDict 中所有字符串都 不同
在这里插入图片描述

#dfs
class Solution:
    def wordBreak(self, s: str, wordDict: List[str]) -> List[str]:
        word_dict=set(wordDict)
        def dfs(i):
            res=[]
            if i==len(s):
                res.append('')
                return res
            #
            for end in range(i+1,len(s)+1):
                if s[i:end] not in word_dict:continue
                strs=dfs(end) 
                #
                for st in strs:
                    split='' if st=='' else ' '
                    res.append(s[i:end]+split+st)#key:各单路径
            return res
        return dfs(0)

lc 91: 解码方法
https://leetcode.cn/problems/decode-ways/
提示:
1 <= s.length <= 100
s 只包含数字,并且可能包含前导零。

#dfs1
class Solution:
    def numDecodings(self, s: str) -> int:
        memo=[-1]*len(s)

        def dfs(i):#以第i个字符开头的子串能解码的个数res
            if i==len(s):return 1
            if memo[i]!=-1:return memo[i] #取不到len(s)+1
            #1)处理左子树
            if s[i]=='0':return 0
            res=0
            res+=dfs(i+1)#end<i+1
            #2)处理右子树
            if i+2<=len(s):
                ten=(ord(s[i])-ord('0'))*10
                one=(ord(s[i+1])-ord('0'))
                if one+ten<=26:
                    res+=dfs(i+2)
            memo[i]=res
            return res
        
        return dfs(0)
#dp1
class Solution:
    def numDecodings(self, s: str) -> int:
        dp=[0]*(len(s)+1)
        dp[len(s)]=1
        #
        for i in range(len(s)-1,-1,-1):
            if s[i]!='0':
                dp[i]+=dp[i+1]#key1
                #
                if i+2<=len(s):
                    ten=(ord(s[i])-ord('0'))*10
                    one=(ord(s[i+1])-ord('0'))
                    if one+ten<=26:
                        dp[i]+=dp[i+2]#key2   
        return dp[0]

#dfs2
#dp2

lc 32:最长有效括号【top100】
https://leetcode.cn/problems/longest-valid-parentheses/
提示:
0 <= s.length <= 3 * 10^4
s[i] 为 ‘(’ 或 ‘)’
在这里插入图片描述
在这里插入图片描述

#方案一:dp
class Solution:
    def longestValidParentheses(self, s: str) -> int:
        n=len(s)
        if n<=1:return 0
        dp=[0]*(n)
        dp[0]=0
        if s[0]=='(' and s[1]==')':dp[1]=2
        #
        res=dp[1]
        for i in range(2,n):
            if s[i]==')':
                if s[i-1]=='(':
                    dp[i]=dp[i-2]+2#()(')'
                elif i-dp[i-1]-1>=0 and s[i-dp[i-1]-1]=='(':#()(()')'
                    dp[i]=dp[i-1]+2+(dp[i-dp[i-1]-2] if i-dp[i-1]-2>=0 else 0)
                res=max(res,dp[i])
        return res

#方案二:栈
class Solution:
    def longestValidParentheses(self, s: str) -> int:
        n=len(s)
        if n<=1:return 0
        stack=deque()#或者用[]
        #
        res=0
        stack.append(-1)
        for i in range(n):
            if s[i]=='(':stack.append(i)
            elif s[i]==')':
                stack.pop()
                if not stack:stack.append(i)
                else:
                    res=max(res,i-stack[-1])
        return res
#方案三:双变量(最优空间)
#o(n),o(1)
class Solution:
    def longestValidParentheses(self, s: str) -> int:
        n=len(s)
        if n<=1:return 0
        #
        res=left=right=0
        for i in range(n):
            if s[i]=='(':left+=1
            else:right+=1
            #
            if left==right:res=max(res,2*left)
            elif left<right:left=right=0
        left=right=0
        for i in range(n-1,-1,-1):
            if s[i]=='(':left+=1
            else:right+=1
            #
            if left==right:res=max(res,2*left)
            elif left>right:left=right=0
        #
        return res

lc 10【剑指 19】【top100】:正则表达式匹配
https://leetcode.cn/problems/regular-expression-matching/
提示:
1 <= s.length <= 20
1 <= p.length <= 30
s 只包含从 a-z 的小写字母。
p 只包含从 a-z 的小写字母,以及字符 . 和 *。
保证每次出现字符 * 时,前面都匹配到有效的字符
在这里插入图片描述
在这里插入图片描述

class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        m,n=len(s),len(p)
        dp=[[False]*(n+1) for _ in range(m+1)]
        dp[0][0]=True
        for j in range(1,n+1):
            if p[j-1]=='*' and (j<=2 or dp[0][j-2]):#"aa""a*"
                dp[0][j]=True
        #
        for i in range(1,m+1):
            for j in range(1,n+1):
                if s[i-1]==p[j-1] or p[j-1]=='.':
                    dp[i][j]=dp[i-1][j-1]
                elif p[j-1]=='*':
                    if s[i-1]==p[j-2] or p[j-2]=='.':#注意".*"的情况
                        dp[i][j]=dp[i][j-2] or dp[i-1][j]
                    else:
                        dp[i][j]=dp[i][j-2]
        return dp[m][n]

lc 718:最长重复子数组
https://leetcode.cn/problems/maximum-length-of-repeated-subarray/
提示:
1 <= nums1.length, nums2.length <= 1000
0 <= nums1[i], nums2[i] <= 100
在这里插入图片描述

class Solution:
    def findLength(self, nums1: List[int], nums2: List[int]) -> int:
        m,n=len(nums1),len(nums2)
        dp=[[0]*(n+1) for _ in range(m+1)]
        res=0
        for i in range(1,m+1):
            for j in range(1,n+1):
                if nums1[i-1]==nums2[j-1]:
                    dp[i][j]=dp[i-1][j-1]+1
                    res=max(res,dp[i][j])
        return res
                

lc 354:俄罗斯套娃信封问题
https://leetcode.cn/problems/russian-doll-envelopes/
提示:
1 <= envelopes.length <= 10^5
envelopes[i].length == 2
1 <= wi, hi <= 10^5
在这里插入图片描述

#dp:o(n^2)超时
#二分法:o(nlogn)
#当另一个信封的宽度和高度都比这个信封大的时候
class Solution:
    def maxEnvelopes(self, envelopes: List[List[int]]) -> int:
        m=len(envelopes)
        envelopes.sort(key=lambda x:(x[0],-x[1]))#key1:宽度递增,高度递减(防止同高度信封的多次利用)
        #
        res=[]#res用于存储所有可套娃信封的高度值
        res.append(envelopes[0][1])
        #key2
        for i in range(1,m):
            curr_hi=envelopes[i][1]
            if curr_hi>res[-1]:
                res.append(curr_hi)
            else:#有益于增加总套数
                index=bisect.bisect_left(res,curr_hi)#加入同宽度,次高度的信封
                res[index]=curr_hi
        return len(res)

lc 152【top100】:乘积最大子数组
https://leetcode.cn/problems/maximum-product-subarray/
提示:
1 <= nums.length <= 2 * 10^4
-10 <= nums[i] <= 10
nums 的任何前缀或后缀的乘积都 保证 是一个 32-位 整数
在这里插入图片描述

#dp
class Solution:
    def maxProduct(self, nums: List[int]) -> int:
        m=len(nums)
        dp_max=[0]*m
        dp_min=[0]*m
        #
        dp_min[0]=dp_max[0]=res=nums[0]
        for i in range(1,m):
            dp_max[i]=max(dp_max[i-1]*nums[i],max(nums[i],dp_min[i-1]*nums[i]))
            dp_min[i]=min(dp_min[i-1]*nums[i],min(nums[i],dp_max[i-1]*nums[i]))  
            res=max(res,dp_max[i])        
        #
        return res      

lc 376:摆动序列
https://leetcode.cn/problems/wiggle-subsequence/
提示:
1 <= nums.length <= 1000
0 <= nums[i] <= 1000
进阶:
你能否用 O(n) 时间复杂度完成此题?
在这里插入图片描述

#方案一:dp
class Solution:
    def wiggleMaxLength(self, nums: List[int]) -> int:
        n=len(nums)
        if n<2:return n
        #
        up,down=[0]*n,[0]*n#注意up=down=[0]*n,地址一直,写法错误
        up[0]=down[0]=1
        for i in range(1,n):
            if nums[i]>nums[i-1]:
                down[i]=down[i-1]
                up[i]=down[i-1]+1
            elif nums[i]<nums[i-1]:
                up[i]=up[i-1]
                down[i]=up[i]+1
            else:
                down[i]=down[i-1]
                up[i]=up[i-1]
        return max(up[n-1],down[n-1])
#方案二:dp+压缩
class Solution:
    def wiggleMaxLength(self, nums: List[int]) -> int:
        n=len(nums)
        if n<2:return n
        #
        up=down=1
        for i in range(1,n):
            if nums[i]>nums[i-1]:
                up=down+1
            elif nums[i]<nums[i-1]:
                down=up+1
        return max(up,down)       

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/179985.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Qt扫盲-QHttpPart类理论总结

QHttpPart类理论总结一、概述二、使用1. 设置头2. 设置内容一、概述 QHttpPart类保存一个主体部分&#xff0c;用于HTTP multipart MIME消息中(由QHttpMultiPart类表示)。 QHttpPart由一个头块和一个数据块组成&#xff0c;它们由两个连续的新行相互分隔。一个部分的例子是: …

智能合约开发——Sui/Move vs. Solana/Rust

1. 引言 前序博客有&#xff1a; zkMove——针对Move合约生态的zkVM 定位为高性能L1的Aptos和Sui&#xff0c;均采用Move合约编程语言。Solana也定位为高性能L1&#xff0c;但其采用Rust合约编程语言。本文重点对比Sui/Move和Solana/Rust合约编程语言。【Aptos/Move为不同的M…

三、Java框架之SpringMVC1_MVC基础

文章目录1. SpringMVC简介1.1 回顾Servlet技术1.2 SpringMVC入门案例步骤1&#xff1a;创建javaweb项目&#xff0c;并导入jar包步骤2&#xff1a;创建Controller步骤3&#xff1a;创建SpringMVC的配置文件步骤4&#xff1a;使用配置类替换web.xml步骤5&#xff1a;启动项目并访…

PyTorch深度学习实践第二讲线性模型

目录监督学习四步骤线性模型泛化代码作业监督学习四步骤 DataSet&#xff08;数据集&#xff09;Model&#xff08;模型选择和设计&#xff0c;例如神经网络&#xff0c;决策树等&#xff09;Training&#xff08;大部分模型都需要训练&#xff0c;都有些例如KNN不需要训练&am…

BFS(四)127. 单词接龙、433. 最小基因变化

目录 127. 单词接龙 433. 最小基因变化 127. 单词接龙 字典 wordList 中从单词 beginWord 和 endWord 的 转换序列 是一个按下述规格形成的序列 beginWord -> s1 -> s2 -> ... -> sk&#xff1a; 每一对相邻的单词只差一个字母。 对于 1 < i < k 时&am…

Qt 6.x中Qt Quick简介及示例

Qt Quick首次在Qt 4.7和Qt Creator 2.1中引入&#xff0c;是一种高级UI技术。 Qt Quick模块是用于编写QML(Qt Meta-Object Language, Qt元对象语言)应用程序的标准库。Qt QML模块提供了QML引擎(engine)和语言基础设施&#xff0c;而Qt Quick模块提供了使用QML创建用户界面…

LCD timing的理解

前言 LCD的时序,之前也有介绍过(深入裸机),但是在介绍这些参数的时候是以感性的认识去理解的,而且多少有些错误,我们以内核文档中的描述为准(Documentation/fb/framebuffer.txt),在结合全志平台来重新正确的理解这些参数。 我们在看下文档中的解释: The frame buffe…

【学习笔记】智能合约引擎

图片来源&#xff1a;https://www.researchgate.net/publication/336453428_Detecting_nondeterministic_payment_bugs_in_Ethereum_smart_contracts/figures?lo1智能合约是区块链技术的核心。我们可以根据以下公式定义智能合约智能合约事务处理和保存机制完备的状态机智能合约…

【手写 Promise 源码】第一篇 - Promise 简介

一&#xff0c;前言 上一篇&#xff0c;完成了 Promise 源码学习的目录&#xff1b; 本篇&#xff0c;主要对 Promise 进行简单的概括介绍&#xff1b; 二&#xff0c;Promise 简介 Promise 是一个类或构造函数&#xff0c;是 JS 原生提供的&#xff0c;通过实例化 Promise …

【Java】还不懂this关键字?一分钟彻底弄懂this关键字

博主简介&#xff1a;努力学习的预备程序媛一枚~博主主页&#xff1a; 是瑶瑶子啦所属专栏: Java岛冒险记【从小白到大佬之路】 前言 问题&#xff1a;为什么会存在this? 在上一篇【JavaSE】一文看懂构造器/构造方法&#xff08;Cunstructor&#xff09;中&#xff0c;我们已…

更方便Spring存储和读取对象,五大类注解、@Bean、@Autowired、@Resource

上一篇博客我们介绍了如何使用xml来引入bean对象&#xff0c;当项目多的时候&#xff0c;显然那样是比较麻烦的。现在我们只需要 个注解就可以替代了。注意&#xff1a;注解和xml可以同时使用准备工作:配置扫描路径我们需要配置 下存储对象的扫描包路径&#xff0c;只有被配置的…

利用Windows系统服务进行权限提升

提权是后渗透重要的一环节&#xff0c;如果当前获取的用户权限比较低&#xff0c;那么我们将无法访问受保护的系统资源或执行系统管理操作&#xff0c;影响后续的攻击过程。这要求我们通过各种手段将当前用户的权限进行提升&#xff0c;以满足后续攻击的要求。利用系统服务提权…

VUE2--22.11.23

VUE2一、Vue.js devtools二、Vue简介1、什么是Vue2、Vue的特性1.数据驱动视图2.双向数据绑定3.MVVM三、Vue的基本使用1、基本使用步骤四、Vue的指令与过滤器1、什么是指令2、内容渲染指令1.v-text2.{{}}3.v-html3、属性绑定指令4、事件绑定指令5、双向绑定指令6、条件渲染指令7…

【Linux】动静态库、文件的三个时间

1.文件的三个时间Access: 访问时间&#xff0c;访问的频率很高&#xff0c;所以较新的Linux都是按一定的时间间隔刷新Modify: 修改文件内容时间Change:修改文件属性时间&#xff0c;修改文件内容也会修改文件属性makefile自动编译判断文件是否为最新&#xff1a;就是按可执行程…

运动基元(一):Dubin‘s曲线【part3】

3.5 RLR RLR的第一段圆弧的曲率 k 1 = − k m a x < 0 → s i g n ( k 1 ) = − 1 k_1=-k_{max}<0\rightarrow si

Springboot图书馆图书借阅管理系统x1x74

目 录 1 概述 1 1.1课题背景及意义 1 1.2 国内外研究现状 1 1.3 本课题主要工作 2 2 系统开发环境 3 2.1 java简介 3 2.2 Mysql数据库 3 2.3 B/S结构 4 2.4 JSP技术介绍 4 3 系统分析 5 3.1 可行性分析 5 3.1.1 技术可行性 5 3.1.2操作…

机器学习sklearn笔记:LDA(线性判别分析)

1 介绍 1.有监督的降维2.投影后类内方差最小&#xff0c;类间方差最大2 推导 我们记最佳的投影向量为w&#xff0c;那么一个样例x到方向向量w上的投影可以表示为&#xff1a; 给定数据集令分别表示第i类的样本个数、样本集合、均值向量和协方差矩阵——>在投影上的均值是 —…

kafka初识

安装kafka 下载 下载window的kafka地址 window的kafka只是为了方便学习 安装地址&#xff1a;kafka.apache.org/ 安装 解压zip为文件夹 启动kafka kafka服务器的功能相当于RocketMQ中的broker&#xff0c;kafka运行还需要一个类似于命名服务器的服务。在kafka安装目录中自…

Windows10添加WebDav地址时报错“输入的文件夹无效,请选择另一个”

一、问题描述在使用Windows10添加WebDav网络地址时&#xff0c;报错“输入的文件夹无效&#xff0c;请选择另一个”&#xff0c;如下图所示&#xff1a;二、问题分析这是由于Windows10的WebDav默认只支持https协议&#xff0c;没有支持http协议导致的。三、解决办法3.1、修改注…

计算机科学领域中里程牌式的算法

计算机科学中伟大的算法前言搜索引擎的索引PageRank公钥加密 --- 用明信片传输秘密纠错码数据压缩无损压缩有损压缩数据库 --- 追求一致性的历程事务和待办事项&#xff08;预写日志记录&#xff09;数字签名用挂锁签名用指数挂锁签名RSA的安全性前言 我肯定不是一位天文学专家…