696. 计数二进制子串
- 给定一个字符串 s,计算具有相同数量0和1的非空(连续)子字符串的数量,并且这些子字符串中的所有0和所有1都是组合在一起的。
重复出现的子串要计算它们出现的次数。
示例:
示例 1 :
输入: "00110011"
输出: 6
解释: 有6个子串具有相同数量的连续1和0:“0011”,“01”,“1100”,“10”,“0011” 和 “01”。
请注意,一些重复出现的子串要计算它们出现的次数。
另外,“00110011”不是有效的子串,因为所有的0(和1)没有组合在一起。
示例 2 :
输入: "10101"
输出: 4
解释: 有4个子串:“10”,“01”,“10”,“01”,它们具有相同数量的连续1和0。
思路1:使用类似寻找回文子串方法
代码实现1:
class Solution:
def countBinarySubstrings(self, s: str) -> int:
if not s:
return 0
n = len(s)
ans = 0
for center in range(2 * n - 1):
left = center // 2
right = center % 2 + left
if left >= 0 and right < n and s[left] == '0' and s[right] == '1':
while left >= 0 and right < n and s[left] == '0' and s[right] == '1':
ans += 1
left -= 1
right += 1
elif left >= 0 and right < n and s[left] == '1' and s[right] == '0':
while left >= 0 and right < n and s[left] == '1' and s[right] == '0':
ans += 1
left -= 1
right += 1
return ans
思路2:按字符分组
- 使用一个group数组,表示字符串中连续重复字符的个数。例如,如果 s=“11000111000000”,则 groups=[2,3,3,6]。
- 根据题目,符合要求的子串,必须出现在两个组之间。如果我们有 groups[i] = 2, groups[i+1] = 3,那么它表示 “00111” 或 “11000”。显然,我们可以在此字符串中生成 min(groups[i], groups[i+1]) 个有效的二进制字符串。
算法:
创建上面定义的 groups。s 的第一个元素属于它自己的组。每个元素要么与前一个元素不匹配,从而开始一个大小为 1 的新组;要么匹配,从而使最近一个组的大小增加 1。
然后,我们将取 min(groups[i-1], groups[i]) 的和。
代码实现2:
class Solution:
def countBinarySubstrings(self, s: str) -> int:
group = [1]
ans = 0
for i in range(1, len(s)):
if s[i] == s[i-1]:
group[-1] += 1
else:
group.append(1)
for i in range(1, len(group)):
ans += min(group[i], group[i-1])
return ans
思路3:线性扫描
按照思路2,若s=“11000111000000”,则 groups=[2,3,3,6]
我们可以只记住 prev = groups[-2] 和 cur=groups[-1] 来代替 groups。
初始定义pre = 0,cur=1,当二进制字符未改变时,cur+1;发生改变时,取pre和cur的最小值,并累加,再将cur的值赋予pre,cur置1。
代码实现:
class Solution:
def countBinarySubstrings(self, s: str) -> int:
ans = 0
pre, cur = 0, 1
for i in range(1, len(s)):
if s[i-1] = s[i]:
cur += 1
else:
ans += min(pre, cur)
pre, cur = cur, 1
# 处理走到最后的情况
ans += min(pre, cur)
return ans
482. 密钥格式化
- 给定一个密钥字符串S,只包含字母,数字以及 ‘-’(破折号)。N 个 ‘-’ 将字符串分成了 N+1 组。给定一个数字 K,重新格式化字符串,除了第一个分组以外,每个分组要包含 K 个字符,第一个分组至少要包含 1 个字符。两个分组之间用 ‘-’(破折号)隔开,并且将所有的小写字母转换为大写字母。
给定非空字符串 S 和数字 K,按照上面描述的规则进行格式化。
示例:
示例 1:
输入:S = "5F3Z-2e-9-w", K = 4
输出:"5F3Z-2E9W"
解释:字符串 S 被分成了两个部分,每部分 4 个字符;
注意,两个额外的破折号需要删掉。
示例 2:
输入:S = "2-5g-3-J", K = 2
输出:"2-5G-3J"
解释:字符串 S 被分成了 3 个部分,按照前面的规则描述,第一部分的字符可以少于给定的数量,其余部分皆为 2 个字符。
提示:
S 的长度不超过 12,000,K 为正整数
S 只包含字母数字(a-z,A-Z,0-9)以及破折号'-'
S 非空
思路:
- 用python库函数处理字符串,去掉’-‘并且转大写
- 字符串长度对K取余,如果有余数,第一个分组先放余数长度个字符
- 每K个字符后放置一个’-’,然后去除原字符串中的K个字符,直到原字符串为空
- 最后去掉末尾多余的’-‘
代码实现:
class Solution:
def licenseKeyFormatting(self, S: str, K: int) -> str:
s = S.replace('-', '').upper()
ret = ''
head = len(s) % K
if head != 0:
ret += s[:head] + '-'
s = s[head:]
while s:
ret += s[:K] + '-'
s = s[K:]
return ret[:-1]
242. 有效的字母异位词
- 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词(字符串长度相等、位置不同)。
示例:
示例 1:
输入: s = "anagram", t = "nagaram"
输出: true
示例 2:
输入: s = "rat", t = "car"
输出: false
思路1:排序
- 判断两字符串长度是否相等,若不相等,直接返回False。
- 通过sorted()方法,查看字符串重新排序后是否相等。
sort 与 sorted 区别:
- sort 是应用在 list 上的方法,sorted 可以对所有可迭代的对象进行排序操作。
- list 的 sort 方法返回的是对已经存在的列表进行操作,无返回值,而内建函数 sorted 方法返回的是一个新的 list,而不是在原来的基础上进行的操作。
思路2:哈希表
- 判断两字符串长度是否相等,若不相等,直接返回False。
- 遍历s字符串,将每个字符与其出现的次数构成映射关系,存入哈希表。
- 遍历t字符串,将每个字符与哈希表的键进行匹配,若匹配到,则将出现次数-1,若匹配不到,设为-1。
- 判断匹配后,字符在哈希表中的值是否小于0,若小于零,说明s字符串中无此字符,直接返回False。
代码实现1:
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
hashmap={}
if len(s) != len(t):
return False
if sorted(s) == sorted(t):
return True
else:
return False
代码实现2:
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
hashmap={}
if len(s) != len(t):
return False
for c in s:
hashmap[c] = hashmap.get(c, 0) + 1
for i in t:
hashmap[i] = hashmap.get(i, 0) - 1
if hashmap[i]<0:
return False
return True
205. 同构字符串
- 给定两个字符串 s 和 t,判断它们是否是同构的。
如果 s 中的字符可以被替换得到 t ,那么这两个字符串是同构的。
所有出现的字符都必须用另一个字符替换,同时保留字符的顺序。两个字符不能映射到同一个字符上,但字符可以映射自己本身。
示例:
示例 1:
输入: s = "egg", t = "add"
输出: true
示例 2:
输入: s = "foo", t = "bar"
输出: false
示例 3:
输入: s = "paper", t = "title"
输出: true
思路1:哈希表
建立
s
−
>
t
s->t
s−>t和
t
−
>
s
t->s
t−>s 之间的映射关系。
遍历s,哈希表中没有当前字符的映射,则添加映射进哈希表,如果映射已经存在,判断当前映射关系是否正确。
遍历t,重复上述操作。
代码实现1:
class Solution:
def isIsomorphic(self, s: str, t: str) -> bool:
hashmap1 = {}
hashmap2 = {}
n = len(s)
# s-->t
for i in range(n):
if s[i] not in hashmap1:
# 如果哈希表中没有当前字符的映射,则添加映射进哈希表
hashmap1[s[i]] = t[i]
elif hashmap1.get(s[i]) != t[i]:
# 如果映射已经存在,但原有映射与当前不同,返回False
return False
# t-->s
for i in range(n):
if t[i] not in hashmap2:
hashmap2[t[i]] = s[i]
elif hashmap2.get(t[i]) != s[i]:
return False
return True
思路2:元素第一次出现的索引
- 使用列表生成式,对s和t进行操作。
- 列表中的每个元素为:字符串的每个元素在字符串中第一次出现的索引值。
- 判等。
代码实现2:
class Solution:
def isIsomorphic(self, s: str, t: str) -> bool:
return [s.index(i) for i in s] == [t.index(i) for i in t]
290. 单词规律
- 给定一种规律 pattern 和一个字符串 str ,判断 str 是否遵循相同的规律。
这里的 遵循 指完全匹配,例如, pattern 里的每个字母和字符串 str 中的每个非空单词之间存在着双向连接的对应规律。
示例:
示例1:
输入: pattern = "abba", str = "dog cat cat dog"
输出: true
示例 2:
输入:pattern = "abba", str = "dog cat cat fish"
输出: false
示例 3:
输入: pattern = "aaaa", str = "dog cat cat dog"
输出: false
示例 4:
输入: pattern = "abba", str = "dog dog dog dog"
输出: false
思路1:哈希表
先将str转为列表lst,判断列表长度与pattern字符串长度是否相等,不相等直接返回False。
建立
p
a
t
t
e
r
n
−
>
l
s
t
pattern->lst
pattern−>lst和
l
s
t
−
>
p
a
t
t
e
r
n
lst->pattern
lst−>pattern 之间的映射关系。
遍历pattern,哈希表中没有当前字符的映射,则添加映射进哈希表,如果映射已经存在,判断当前映射关系是否正确。
遍历str,重复上述操作。
代码实现1:
class Solution:
def wordPattern(self, pattern: str, str: str) -> bool:
hashmap1 = {}
hashmap2 = {}
lst = str.split(' ')
if len(pattern) != len(lst):
return False
for i in range(len(pattern)):
if pattern[i] not in hashmap1:
hashmap1[pattern[i]] = lst[i]
elif hashmap1.get(pattern[i]) != lst[i]:
return False
for i in range(len(pattern)):
if lst[i] not in hashmap2:
hashmap2[lst[i]] = pattern[i]
elif hashmap2.get(lst[i]) != pattern[i]:
return False
return True
思路2:元素第一次出现的索引
- 使用列表生成式,对pattren和str进行操作,str需转为列表。
- 列表中的每个元素为:字符串的每个元素在字符串中第一次出现的索引值。
- 判等。
代码实现2:
class Solution:
def wordPattern(self, pattern: str, str: str) -> bool:
a = [pattern.index(i) for i in pattern]
lst = str.split(' ')
b = [lst.index(i) for i in lst]
return a == b