1.23刷题日记:贪心算法

还是贪心,今天浅试一下困难程度的,一题中等,一题困难

334. 递增的三元子序列

给你一个整数数组 nums ,判断这个数组中是否存在长度为 3 的递增子序列。

如果存在这样的三元组下标 (i, j, k) 且满足 i < j < k ,使得 nums[i] < nums[j] < nums[k] ,返回 true ;否则,返回 false 。

示例 1:

输入:nums = [1,2,3,4,5]
输出:true
解释:任何 i < j < k 的三元组都满足题意

示例 2:

输入:nums = [5,4,3,2,1]
输出:false
解释:不存在满足题意的三元组
class Solution:
    def increasingTriplet(self, nums: List[int]) -> bool:
        one = two = float('inf')
        for three in nums:
            if three > two: return True
            elif three <= one: one = three
            else: two = three
        return False

44. 通配符匹配

给你一个输入字符串 (s) 和一个字符模式 (p) ,请你实现一个支持 '?' 和 '*' 匹配规则的通配符匹配:

  • '?' 可以匹配任何单个字符。
  • '*' 可以匹配任意字符序列(包括空字符序列)。

判定匹配成功的充要条件是:字符模式必须能够 完全匹配 输入字符串(而不是部分匹配)。

 

示例 1:

输入:s = "aa", p = "a"
输出:false
解释:"a" 无法匹配 "aa" 整个字符串。

示例 2:

输入:s = "aa", p = "*"
输出:true
解释:'*' 可以匹配任意字符串。

示例 3:

输入:s = "cb", p = "?a"
输出:false
解释:'?' 可以匹配 'c', 但第二个 'a' 无法匹配 'b'。

但是*也可以和a~z之间的小写字母随意排列

这题贪心对我太难了,还是看官方题解吧

我们以 p=∗ abcd ∗为例,p 可以匹配所有包含子串 abcd 的字符串,也就是说,我们只需要暴力地枚举字符串 s 中的每个位置作为起始位置,并判断对应的子串是否为 abcd即可。这种暴力方法的时间复杂度为 O(mn)O(mn)O(mn),与动态规划一致,但不需要额外的空间。

如果 p=∗ abcd∗efgh∗i ∗ 呢?显然,p可以匹配所有依次出现子串 abcd、efgh、i 的字符串。此时,对于任意一个字符串 s,我们首先暴力找到最早出现的 abcd,随后从下一个位置开始暴力找到最早出现的 efgh,最后找出 i,就可以判断 s 是否可以与 p匹配。这样「贪心地」找到最早出现的子串是比较直观的,因为如果 s 中多次出现了某个子串,那么我们选择最早出现的位置,可以使得后续子串能被找到的机会更大。

因此,如果模式 p的形式为 ∗ u1∗u2∗u3 ∗⋯∗ux ∗即字符串(可以为空)和星号交替出现,并且首尾字符均为星号,那么我们就可以设计出下面这个基于贪心的暴力匹配算法。算法的本质是:如果在字符串 s 中首先找到 u 1 ,再找到 u2,u3,⋯ ,ux  ,那么 s 就可以与模式 p 匹配,伪代码如下:

// 我们用 sIndex 和 pIndex 表示当前遍历到 s 和 p 的位置
// 此时我们正在 s 中寻找某个 u_i
// 其在 s 和 p 中的起始位置为 sRecord 和 pRecord

// sIndex 和 sRecord 的初始值为 0
// 即我们从字符串 s 的首位开始匹配
sIndex = sRecord = 0

// pIndex 和 pRecord 的初始值为 1
// 这是因为模式 p 的首位是星号,那么 u_1 的起始位置为 1
pIndex = pRecord = 1

while sIndex < s.length and pIndex < p.length do
    if p[pIndex] == '*' then
        // 如果遇到星号,说明找到了 u_i,开始寻找 u_i+1
        pIndex += 1
        // 记录下起始位置
        sRecord = sIndex
        pRecord = pIndex
    else if match(s[sIndex], p[pIndex]) then
        // 如果两个字符可以匹配,就继续寻找 u_i 的下一个字符
        sIndex += 1
        pIndex += 1
    else if sRecord + 1 < s.length then
        // 如果两个字符不匹配,那么需要重新寻找 u_i
        // 枚举下一个 s 中的起始位置
        sRecord += 1
        sIndex = sRecord
        pIndex = pRecord
    else
        // 如果不匹配并且下一个起始位置不存在,那么匹配失败
        return False
    end if
end while

// 由于 p 的最后一个字符是星号,那么 s 未匹配完,那么没有关系
// 但如果 p 没有匹配完,那么 p 剩余的字符必须都是星号
return all(p[pIndex] ~ p[p.length - 1] == '*')

作者:力扣官方题解
链接:https://leetcode.cn/problems/wildcard-matching/solutions/315802/tong-pei-fu-pi-pei-by-leetcode-solution/


然而模式 p并不一定是 ∗ u1∗u2∗u3 ∗⋯∗ux ∗的形式:

模式 p的开头字符不是星号;

模式 p的结尾字符不是星号。

第二种情况处理起来并不复杂。如果模式 p的结尾字符不是星号,那么就必须与字符串 s 的结尾字符匹配。那么我们不断地匹配 s 和 p 的结尾字符,直到 p 为空或者 p 的结尾字符是星号为止。在这个过程中,如果匹配失败,或者最后 p 为空但 s 不为空,那么需要返回 False

第一种情况的处理也很类似,我们可以不断地匹配 s 和 p 的开头字符。下面的代码中给出了另一种处理方法,即修改 sRecord和 tRecord 的初始值为 −1,表示模式 p 的开头字符不是星号,并且在匹配失败时进行判断,如果它们的值仍然为 −1,说明没有「反悔」重新进行匹配的机会。

class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        def allStars(st: str, left: int, right: int) -> bool:
            return all(st[i] == '*' for i in range(left, right))
        
        def charMatch(u: str, v: str) -> bool:
            return u == v or v == '?'

        sRight, pRight = len(s), len(p)
        while sRight > 0 and pRight > 0 and p[pRight - 1] != '*':
            if charMatch(s[sRight - 1], p[pRight - 1]):
                sRight -= 1
                pRight -= 1
            else:
                return False
        
        if pRight == 0:
            return sRight == 0
        
        sIndex, pIndex = 0, 0
        sRecord, pRecord = -1, -1
        while sIndex < sRight and pIndex < pRight:
            if p[pIndex] == '*':
                pIndex += 1
                sRecord, pRecord = sIndex, pIndex
            elif charMatch(s[sIndex], p[pIndex]):
                sIndex += 1
                pIndex += 1
            elif sRecord != -1 and sRecord + 1 < sRight:
                sRecord += 1
                sIndex, pIndex = sRecord, pRecord
            else:
                return False

        return allStars(p, pIndex, pRight)

作者:力扣官方题解
链接:https://leetcode.cn/problems/wildcard-matching/solutions/315802/tong-pei-fu-pi-pei-by-leetcode-solution/

我还是没有很懂贪心这种东西,真的,我真的可能......脑子有点不太方便吧,总之遇到编程算法就不太够用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值