字符串

1. 字符串循环移位包含

s1 = AABCD, s2 = CDAA
Return : true

给定两个字符串 s1 和 s2,要求判定 s2 是否能够被 s1 做循环移位得到的字符串包含。

s1 进行循环移位的结果是 s1s1 的子字符串,因此只要判断 s2 是否是 s1s1 的子字符串即可。

def isContainsByConcal(a, b):
    if not a or not b: return False
    new_a = a + a
    return b in new_a

2. 字符串循环移位

s = "abcd123" k = 3
Return "123abcd"

将字符串向右循环移动 k 位。

将 abcd123 中的 abcd 和 123 单独翻转,得到 dcba321,然后对整个字符串进行翻转,得到 123abcd。

def leftloop(lst, k):
    return lst[k:] + lst[:k]
def leftloop(lst, k):
    new = lst[:k][::-1] + lst[k:][::-1]
    return new[::-1]

3. 字符串中单词的翻转

s = "I am a student"
Return "student a am I"

将每个单词翻转,然后将整个字符串翻转。

def revereseWords(s):
    ls = s.split(" ")
    new_str = ls.reverse()
    return " ".join(new_str)

4. 两个字符串包含的字符是否完全相同

给定两个字符串 st ,编写一个函数来判断 t 是否是 s 的字母异位词。

s = "anagram", t = "nagaram", return true.
s = "rat", t = "car", return false.

可以用 HashMap 来映射字符与出现次数,然后比较两个字符串出现的字符数量是否相同。

由于本题的字符串只包含 26 个小写字符,因此可以使用长度为 26 的整型数组对字符串出现的字符进行统计,不再使用 HashMap。

class Solution:
    def isAnagram(self, s: str, t: str) -> bool:
        cnts = [0] * 26
        for c in s:
            cnts[ord(c) - ord('a')] += 1
        for c in t:
            cnts[ord(c) - ord('a')] -= 1
        for cnt in cnts:
            if cnt != 0:
                return False
        return True

5. 计算一组字符集合可以组成的回文字符串的最大长度

给定一个包含大写字母和小写字母的字符串,找到通过这些字母构造成的最长的回文串。

在构造过程中,请注意区分大小写。比如 "Aa" 不能当做一个回文字符串。

Input : "abccccdd"
Output : 7
我们可以构造的最长的回文串是"dccaccd", 它的长度是 7。

使用长度为 256 的整型数组来统计每个字符出现的个数,每个字符有偶数个可以用来构成回文字符串。

因为回文字符串最中间的那个字符可以单独出现,所以如果有单独的字符就把它放到最中间。

class Solution:
    def longestPalindrome(self, s: str) -> int:
        cnts = [0] * 256
        for c in s:
            cnts[ord(c)] += 1
        palindrome = 0
        for cnt in cnts:
            palindrome += cnt // 2 * 2
        if palindrome < len(s):
            palindrome += 1  # 这个条件下 s 中一定有单个未使用的字符存在,可以把这个字符放到回文的最中间
        return palindrome

6. 字符串同构

给定两个字符串 s 和 t,判断它们是否是同构的。

如果 s 中的字符可以被替换得到 t ,那么这两个字符串是同构的。

所有出现的字符都必须用另一个字符替换,同时保留字符的顺序。两个字符不能映射到同一个字符上,但字符可以映射自己本身。 假设 st 具有相同的长度。

Given "egg", "add", return true.
Given "foo", "bar", return false.
Given "paper", "title", return true.

记录一个字符上次出现的位置,如果两个字符串中的字符上次出现的位置一样,那么就属于同构。

class Solution:
    def isIsomorphic(self, s: str, t: str) -> bool:
        preIndexOfS = [0] * 256
        preIndexOfT = [0] * 256
        for i in range(len(s)):
            if preIndexOfS[ord(s[i])] != preIndexOfT[ord(t[i])]:
                return False
            preIndexOfS[ord(s[i])] = i + 1  # 记录位置信息
            preIndexOfT[ord(t[i])] = i + 1
        return True

将 s 与 t 中的元素利用哈希表 (字典) 一一对应,后面重复的字符与哈希表中字符对应规则一致则说明同构。

class Solution(object):
    def isIsomorphic(self, s, t):
        if not s:
            return True
        dic = {}
        for i in range(len(s)):
            if s[i] not in dic:
                if t[i] in dic.values():
                    return False
                else:
                    dic[s[i]] = t[i]
            else:
                if dic[s[i]] != t[i]:
                    return False
        return True

7. 回文子字符串个数

给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。

具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被计为是不同的子串。

输入: "aaa"
输出: 6
说明: 6个回文子串: "a", "a", "a", "aa", "aa", "aaa".

在长度为 N 的字符串中,可能的回文串中心位置有 2N-1 个:一个字母,或两个字母中间。

从每一个回文串中心开始统计回文串数量。回文区间 [a, b] 表示 S[a], S[a+1], …, S[b] 是回文串,根据回文串定义可知 [a+1, b-1] 也是回文区间。

class Solution(object):
    def countSubstrings(self, S):
        N = len(S)
        ans = 0
        for center in range(2*N - 1):
            left = center // 2  # center 为奇数时,center 为两字母之间,;left、right 分别为两字母位置的下标
            right = left + center % 2  # 偶数时,left、right 为中心位置的下标
            while left >= 0 and right < N and S[left] == S[right]:
                ans += 1
                left -= 1
                right += 1
        return ans

从字符串的某一位开始,尝试着去扩展子字符串。

class Solution:
    def countSubstrings(self, s: str) -> int:
        self.ans = 0
        
        def extendSubStrings(s, start, end):
            while start >= 0 and end < len(s) and s[start] == s[end]:
                start -= 1
                end += 1
                self.ans += 1

        for i in range(len(s)):
            extendSubStrings(s, i, i)
            extendSubStrings(s, i, i + 1)
        return self.ans

8. 判断一个整数是否是回文数

要求不能使用额外空间,也就不能将整数转换为字符串进行判断。

将整数翻转:

class Solution:
    def isPalindrome(self, x: int) -> bool:
        if x < 0:
            return False
        cur = 0
        num = x
        while num != 0:
            cur = cur * 10 + num % 10
            num = num // 10
        return x == cur

将整数分成左右两部分,右边那部分需要转置,然后判断这两部分是否相等。

class Solution:
    def isPalindrome(self, x: int) -> bool:
        if x == 0: return True
        if x < 0 or x % 10 == 0: return False
        right = 0
        while x > right:
            right = right * 10 + x % 10
            x = x // 10
        return x == right or x == right // 10

9. 统计二进制字符串中连续 1 和连续 0 数量相同的子字符串个数

输入: "00110011"
输出: 6
解释:6个子串具有相同数量的连续10:“0011”,“01”,“1100”,“10”,“0011” 和 “01”。
  • 按字符分组:
  1. 将字符串 s 转换为 groups 数组表示字符串中相同字符连续块的长度。例如,如果 s=“11000111000000”,则 groups=[2,3,3,6]
  2. 计算 groups[i] 和 groups[i+1] 之间的有效二进制字符串数。如果我们有 groups[i] = 2, groups[i+1] = 3,那么它表示 “00111” 或 “11000”。显然,我们可以在此字符串中生成 min(groups[i], groups[i+1]) 有效的二进制字符串。
class Solution(object):
    def countBinarySubstrings(self, s):
        groups = [1]
        for i in range(1, len(s)):
            if s[i-1] != s[i]:
                groups.append(1)
            else:
                groups[-1] += 1

        ans = 0
        for i in range(1, len(groups)):
            ans += min(groups[i-1], groups[i])
        return ans
  • 线性扫描:

修改我们的方法 1 来实时计算答案。我们将**只记住 prev = groups[-2] 和 cur=groups[-1] **来代替 groups。然后,答案是我们看到的每个不同的 (prev, cur) 的 min(prev, cur) 之和。

class Solution(object):
    def countBinarySubstrings(self, s):
        ans, prev, cur = 0, 0, 1
        for i in range(1, len(s)):
            if s[i-1] != s[i]:
                ans += min(prev, cur)
                prev, cur = cur, 1
            else:
                cur += 1  # 记录当前重复的字符

        return ans + min(prev, cur)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值