力扣算法----------字符串一

1 无重复字符的最长子串

>  最常见的就是本办法不断的循环获取各个区间,在不同的区间进行判断  

>  采用双指针+字典的方式进行位置保存,跳过无效位置的无效判断,本质上双指针就是确定有效区间的起点和终点。

第一种方法:
class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        if not s:
            return 0
        def getqu(i, j):
            return s[i:j+1]
        def just(cur):
            dic = {}
            for i in cur:
                if i not in dic:
                    dic[i] = 1
                else:
                    return False
            return True
        max_ = 0
        for i in range(len(s)):
            for j in range(len(s)):
                if just(getqu(i, j)):
                    max_ = max(max_, j-i+1)
        return max_
第二种方法:
class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        if not s:
            return 0
        max_ = 0
        dic = {}
        start = 0
        index = 0
        while index < len(s):
            cur = s[index]
            if cur in dic:
                # 新字符重复后,有效长度是当前重复字符前一个位置到上次重复字符的后一个位置
                # 其实就是确定不重复字段的起点终点,
                # 所以结果是index-1 - start + 1 = index - start
                max_ = max(max_, index - start)
                start = max(start, dic[cur] + 1)  # 注意start有可能回缩
            dic[cur] = index
            index += 1
        return max(max_, index - start)  # 考虑到最后字符不再dic中,会造成长度增加

2.最长回文子串

其实本质上就是三种做法:官方写法:官方解读

第一是时间复杂度是O(n^2),空间复杂度也是O(n^2),这里使用的动态规划的思想   熟悉动态规划

第二是时间复杂度是O(n^2),空间复杂度是O(1),这里使用的是最直接的想法,就是找中点,左右两侧扩展

第三是相对比较复杂的Manacher算法,具体可以查看力扣的解读。  熟悉空间换时间  熟悉利用前面的思想  还是动态规划

解析链接:下面三句话至关重要,要仔细理解

方法一:本质上是设置二维数组,然后动态规划的方程就是p(i+1,j-1) = True and s[i] == s[j],这个
这就是回文串,默认至少2个字符,所以初始化二维数组需要先将二个字符的初始化了(即初始化对角线以及对角线的右上线),这句话既是初始化数组方法,也是暗含了对于奇数和偶数回文串的两种情况,主对角线是奇数,次主对角线是偶数。

从执行过程分析是按照斜对角的方式由右下到左上不断的迭代,直到迭代到右上角。

从本质上分析其实就是枚举罗列的办法,也会dp类方法有更加深刻的认识。
class Solution:
    # 动态规划使用python会超时  也不是换种更加简便的方法就不超时了
    def longestPalindrome(self, s: str) -> str:
        if not s:
            return None
        if len(s) == 1:
            return s
        # 定义返回函数
        def getCur(i, j, cur):
            if j-i+1 > len(cur):
                return s[i:j+1]
            return cur
        # 初始化主对角线
        cur = s[0]
        dp = [[True if i == j else False for i in range(len(s))] for j in range(len(s))]
        # 初始化右斜对角线
        for i in range(len(s)-2, -1, -1):
            j = i+1
            if s[i] == s[j]:
                dp[i][j] = True
                cur = getCur(i, j, cur)
            else:
                dp[i][j] = False
        # 开始迭代
        for line in range(len(s)-3, -1, -1):
            for i in range(line, -1, -1):
                j = i+(len(s)-line-1)
                if s[i] == s[j] and dp[i+1][j-1]:
                    dp[i][j] = True
                    cur = getCur(i, j, cur)
                else:
                    dp[i][j] = False
        return cur
        
方法二:中心扩散法   考试的话可以说动态规划的思路,但是写的话还是写这种方法吧,空间复杂度是1
class Solution:
    def longestPalindrome(self, s: str) -> str:
        if (not s or len(s) == 1):
            return s
        cur = s[0]
        for i in range(len(s)):
            def adjustQ(i, cur):
                left = i - 1
                right = i + 1
                while left >= 0 and right < len(s) and s[left] == s[right]:
                    left -= 1
                    right += 1
                left += 1
                right -= 1
                return s[left:right + 1] if right - left + 1 > len(cur) else cur

            def adjustO(i, cur):
                p = i + 1
                if p >= len(s) or s[i] != s[p]:
                    return cur
                left = i - 1
                right = i + 2
                while left >= 0 and right < len(s) and s[left] == s[right]:
                    left -= 1
                    right += 1
                left += 1
                right -= 1
                return s[left:right + 1] if right - left + 1 > len(cur) else cur

            cur = adjustQ(i, cur)
            cur = adjustO(i, cur)
        return cur

方法三:https://ethsonliu.com/2018/04/manacher.html  这个链接分析的还可以
class Solution:
    def longestPalindrome(self, s: str) -> str:
        if (not s or len(s) == 1):
            return s
        s = '#' + '#'.join(list(s)) + '#'
        maxRight = 0
        center = 0
        iToLenth = [0]
        cur = s[0]
        indexMax = 0
        maxLenth = iToLenth[indexMax]
        for i, charCur in enumerate(s[1:], 1):
            if i > maxRight:  # 运动到了右界之后,需要新的中心扩展
                iToLenth.append(0)
                left = i - 1
                right = i + 1
            else:  # 在右界内部,获取点关于对称点的对称值,切记下面的公式
                iToLenth.append(min(iToLenth[2 * center - i], maxRight-i))
                left = i - (iToLenth[i] + 1)
                right = i + (iToLenth[i] + 1)
            while left >= 0 and right < len(s) and s[left] == s[right]:
                left -= 1
                right += 1
                iToLenth[i] += 1
            if iToLenth[i] + i > maxRight:
                maxRight = i + iToLenth[i]
                center = i
            if iToLenth[i] > maxLenth:
                maxLenth = iToLenth[i]
                indexMax = i
        return s[indexMax-maxLenth+1:indexMax+maxLenth+1:2]

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值