Leetcode - 字符串(一)

目录

1180. 统计只含单一字母的子串

893. 特殊等价字符串组


1180. 统计只含单一字母的子串

https://leetcode-cn.com/problems/count-substrings-with-only-one-distinct-letter/

给你一个字符串 S,返回只含 单一字母 的子串个数。

示例 1:输入: "aaaba",输出: 8
解释: 只含单一字母的子串分别是 "aaa", "aa", "a", "b"。
"aaa" 出现 1 次。"aa" 出现 2 次。"a" 出现 4 次。"b" 出现 1 次。所以答案是 1 + 2 + 4 + 1 = 8。
示例 2:输入: "aaaaaaaaaa",输出: 55
提示:1 <= S.length <= 1000,S[i] 仅由小写英文字母组成。

题解

一:pre用来记录前一个字符,若相同,将该字符加入s,并用来计算加入一个字符带来的res的增加,我们可以知道,一个字符个数加1(两个字符数加1...整个s长度的字符个数加1),故我们可以知道增加的个数是加入该字符后,字符串的长度。若不相同,加的个数是1.其实我们并不关心s是啥,只关心其长度,可以优化一下空间,以及时间效率(字符串赋值带来的开销).

class Solution(object):
    def countLetters(self, S):
        """
        :type S: str
        :rtype: int
        """
        s, pre, res = "", None, 0

        for c in S:
            if c == pre:
                s += c
                res += len(s)
            else:
                s = c
                res += 1
                pre = c
        return res
class Solution(object):
    def countLetters(self, S):
        local_len, pre, res = 0, None, 0

        for c in S:
            if c == pre:
                local_len += 1
                res += local_len
            else:
                local_len = 1
                res += local_len
                pre = c
        return res

893. 特殊等价字符串组

https://leetcode-cn.com/problems/groups-of-special-equivalent-strings/

你将得到一个字符串数组 A。每次移动都可以交换 S 的任意两个偶数下标的字符或任意两个奇数下标的字符。如果经过任意次数的移动,S == T,那么两个字符串 S 和 T 是 特殊等价 的。

例如,S = "zzxy" 和 T = "xyzz" 是一对特殊等价字符串,因为可以先交换 S[0] 和 S[2],然后交换 S[1] 和 S[3],使得 "zzxy" -> "xzzy" -> "xyzz" 。

现在规定,A 的 一组特殊等价字符串 就是 A 的一个同时满足下述条件的非空子集:

  • 该组中的每一对字符串都是 特殊等价 的
  • 该组字符串已经涵盖了该类别中的所有特殊等价字符串,容量达到理论上的最大值(也就是说,如果一个字符串不在该组中,那么这个字符串就 不会 与该组内任何字符串特殊等价)

返回 A 中特殊等价字符串组的数量。

提示:1 <= A.length <= 1000,1 <= A[i].length <= 20,所有 A[i] 都具有相同的长度。所有 A[i] 都只由小写字母组成。

题解

一:仔细思考一下,其实只要偶数位上的字符的组合一样,奇数位上的字符的组合也一样的话,就是特殊等价,因为只要偶数位一样,那么我们通过偶数位的两两交换必能相等,奇数位同理。我们用rec[i]数组来记录偶数位和奇数位的字符的个数,0-25是偶数位,26-51是奇数位。然后比较的时候,只要这52个元素对应相等就ok了,已经和一个字符串(B)特殊等价了,所有能特殊等价的必定也和(B)等价,也不会和不能和B等价的等价,所以只要等价了,后面就可以不用就比较了。

class Solution(object):
    def numSpecialEquivGroups(self, A):
        """
        :type A: List[str]
        :rtype: int
        """
        def is_equiv(x, y):
            for j in range(52):
                if rec[x][j] != rec[y][j]:
                    return False 
            return True

        res, n = 0, len(A) 
        equiv = [False] * n 
        rec = [[0] * 52 for _ in range(n)]
        
        for i in range(n):
            for j in range(len(A[i])):
                idx = (j % 2) * 26 + ord(A[i][j]) - ord('a')
                rec[i][idx] += 1
        
        for i in range(n):
            if equiv[i]:
                continue 
            for j in range(i + 1, n):
                if equiv[j]:
                    continue 
                if is_equiv(i, j):
                    equiv[j] = True 
            res += 1
                
        return res

二:在法一的基础上,我们将rec数组映射成字符串,用集合来帮助去重。

class Solution(object):
    def numSpecialEquivGroups(self, A):
        n = len(A)
        rec = [[0] * 52 for _ in range(n)]

        for i in range(n):
            for j in range(len(A[i])):
                idx = ord(A[i][j]) - ord('a')
                rec[i][(j % 2) * 26 + idx] += 1

        return len({''.join(str(c) for c in rec[i]) for i in range(n)})

459. 重复的子字符串

https://leetcode-cn.com/problems/repeated-substring-pattern/

给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。

示例 1:输入: "abab",输出: True。解释: 可由子字符串 "ab" 重复两次构成。
示例 2:输入: "aba",输出: False
示例 3:输入: "abcabcabcabc",输出: True。解释: 可由子字符串 "abc" 重复四次构成。 (或者子字符串 "abcabc" 重复两次构成。)

题解

一:

class Solution(object):
    def repeatedSubstringPattern(self, s):
        """
        :type s: str
        :rtype: bool
        """
        if not s:
            return True
        for i in range(len(s)):
            # 整个字符串的长度必定是s[:i + 1]的倍数,否则s[:i + 1]不可能是重复单元
            if len(s) % (i + 1) != 0:
                continue 
            if i == len(s) - 1:
                return False
            length = i + 1
            flag = True
            for j in range(i + 1, len(s), length):
                end = min(len(s), j + length)
                if s[j: end] != s[: i + 1]:
                    flag = False 
                    break 
            if flag:
                return True 

        return False

二:转自https://leetcode-cn.com/problems/repeated-substring-pattern/solution/jian-dan-ming-liao-guan-yu-javaliang-xing-dai-ma-s/

如果您的字符串S包含一个重复的子字符串,那么这意味着您可以多次“移位和换行”您的字符串,并使其与原始字符串匹配。
例如:abcabc
移位一次:cabcab
移位两次:bcabca
移位三次:abcabc

现在字符串和原字符串匹配了,所以可以得出结论存在重复的子串

基于这个思想,可以每次移动k个字符,直到匹配移动length - 1次。但是这样对于重复字符串很长的字符串,效率会非常低。在LeetCode中执行时间超时了。为了避免这种无用的环绕,可以创建一个新的字符串str,它等于原来的字符串S再加上S自身,这样其实就包含了所有移动的字符串。

比如字符串:S = acd,那么str = S + S = acdacd

acd移动的可能:dac、cda。其实都包含在了str中了。就像一个滑动窗口

一开始acd (acd) ,移动一次ac(dac)d,移动两次a(cda)cd。循环结束

所以可以直接判断str中去除首尾元素之后,是否包含自身元素。如果包含。则表明存在重复子串。

class Solution(object):
    def repeatedSubstringPattern(self, s):
        return s in (s + s)[1: -1]

 

 

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值