文章目录
242. 有效的字母异位词(字符串)
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
-
示例 1:
输入: s = “anagram”, t = “nagaram”
输出: true -
示例 2:
输入: s = “rat”, t = “car”
输出: false
说明:
你可以假设字符串只包含小写字母。 -
进阶:
如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况?
1)列表
一个简单的思路是转化为列表,遍历第一个列表的元素,判断第二个列表中是否存在,如果存在,从第二个列表中剔除该元素,最终,如果第二个列表为空,则返回 true,否则返回 false
class Solution(object):
def isAnagram(self, s, t):
"""
:type s: str
:type t: str
:rtype: bool
"""
list1 = list(s)
list2 = list(t)
if len(list1)!= len(list2):
return False
for i in list1:
if i in list2:
list2.remove(i)
else:
break
if list2 == []:
return True
else:
return False
2)用 set 和 count 就快很多
class Solution(object):
def isAnagram(self, s, t):
"""
:type s: str
:type t: str
:rtype: bool
"""
if len(s)!= len(t):
return False
set1 = set(s)
for i in set1:
if s.count(i) != t.count(i):
return False
return True
709. 转换成小写字母(ASCII)
实现函数 ToLowerCase(),该函数接收一个字符串参数 str,并将该字符串中的大写字母转换成小写字母,之后返回新的字符串。
-
示例 1:
输入: “Hello”
输出: “hello” -
示例 2:
输入: “here”
输出: “here” -
示例 3:
输入: “LOVELY”
输出: “lovely”
思路:用 ASCII
ord(char) = ASCII
chr(ASCII) = char
class Solution(object):
def toLowerCase(self, str):
"""
:type str: str
:rtype: str
"""
diff = ord("a") - ord("A")
result = ""
for s in str:
if ord("A") <= ord(s) <= ord("Z"): # 小于97 就是大写字母
result+=chr(ord(s) + diff)
else:
result+=s
return result
830. 较大分组的位置
在一个由小写字母构成的字符串 S 中,包含由一些连续的相同字符所构成的分组。
例如,在字符串 S = “abbxxxxzyy” 中,就含有 “a”, “bb”, “xxxx”, “z” 和 “yy” 这样的一些分组。
我们称所有包含大于或等于三个连续字符的分组为较大分组。找到每一个较大分组的起始和终止位置。
最终结果按照字典顺序输出。
-
示例 1:
输入: “abbxxxxzzy”
输出: [[3,6]]
解释: “xxxx” 是一个起始于 3 且终止于 6 的较大分组。 -
示例 2:
输入: “abc”
输出: []
解释: “a”,“b” 和 “c” 均不是符合要求的较大分组。 -
示例 3:
输入: “abcdddeeeeaabbbcd”
输出: [[3,5],[6,9],[12,14]]
说明: 1 <= S.length <= 1000
思路:遍历一次,判断相邻元素是否相等,计数,注意边界情况
class Solution(object):
def largeGroupPositions(self, S):
"""
:type S: str
:rtype: List[List[int]]
"""
list1 = []
count = 1 # 统计重复频次
for i in range(len(S)-1): # 遍历第一个到倒数第二个,这种遍历方法忽略了最后一项,所以要if i==len(S)-2
if S[i]==S[i+1]: # 判断相邻的元素是否相等
count+=1
if i == len(S)-2 and count>=3: # 最后两个元素也相等且长度超过3了
list1.append([i+1-count+1,i+1])
else:
if count>= 3:
list1.append([i-count+1,i])
count = 1
return list1
228. 汇总区间
给定一个无重复元素的有序整数数组,返回数组区间范围的汇总。
-
示例 1:
输入: [0,1,2,4,5,7]
输出: [“0->2”,“4->5”,“7”]
解释: 0,1,2 可组成一个连续的区间; 4,5 可组成一个连续的区间。 -
示例 2:
输入: [0,2,3,4,6,8,9]
输出: [“0”,“2->4”,“6”,“8->9”]
解释: 2,3,4 可组成一个连续的区间; 8,9 可组成一个连续的区间。
思路:这个题是 830 的升级版,要给出递增序列的区间,方法可以同 830,只是这种思路下边界情况要复杂一些
class Solution(object):
def summaryRanges(self, nums):
"""
:type nums: List[int]
:rtype: List[str]
"""
if len(nums) == 1: # 只有一个元素,直接输出结果
return [str(nums[0])]
count = 1 # 统计重复元素的个数
list1 = []
for i in range(len(nums)-1): # 遍历第一个到倒数第二个元素,这种遍历方法忽略了最后一项,所以要if i==len(S)-2
if nums[i]+1 == nums[i+1]: # 如果相邻元素续上了
count+=1
if i==len(nums)-2: # 如果遍历到了倒数第二个且和最后元素续上了
list1.append(str(nums[i+1-count+1])+"->"+str(nums[i+1]))
else: # 相邻元素不相等
if count>1: # 加入范围
list1.append(str(nums[i-count+1])+"->"+str(nums[i]))
else: # count=1,加入单个元素
list1.append(str(nums[i]))
# 遍历到倒数第二个且不和最后元素续上了,添加单个最后的元素
if i==len(nums)-2:
list1.append(str(nums[i+1]))
count=1
return list1
344. 反转字符串([::-1])
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
思路:两个指针,头到尾巴,尾到头,两个交换
class Solution(object):
def reverseString(self, s):
"""
:type s: List[str]
:rtype: None Do not return anything, modify s in-place instead.
"""
if s == []:
pass
else:
for i in range(len(s)/2):
s[i],s[len(s)-i-1] = s[len(s)-i-1],s[i]
s = s[::-1] 失败了
这样才行,一行搞定
s[:] = s[::-1]
929. 独特的电子邮件地址(split)
每封电子邮件都由一个本地名称和一个域名组成,以 @ 符号分隔。
例如,在 alice@leetcode.com中, alice 是本地名称,而 leetcode.com 是域名。
除了小写字母,这些电子邮件还可能包含 ‘.’ 或 ‘+’。
如果在电子邮件地址的本地名称部分中的某些字符之间添加句点(‘.’),则发往那里的邮件将会转发到本地名称中没有点的同一地址。例如,"alice.z@leetcode.com” 和 “alicez@leetcode.com” 会转发到同一电子邮件地址。 (请注意,此规则不适用于域名。)
如果在本地名称中添加加号(‘+’),则会忽略第一个加号后面的所有内容。这允许过滤某些电子邮件,例如 m.y+name@email.com 将转发到 my@email.com。 (同样,此规则不适用于域名。)
可以同时使用这两个规则。
给定电子邮件列表 emails,我们会向列表中的每个地址发送一封电子邮件。实际收到邮件的不同地址有多少?
示例:
输入:[“test.email+alex@leetcode.com”,“test.e.mail+bob.cathy@leetcode.com”,“testemail+david@lee.tcode.com”]
输出:2
解释:实际收到邮件的是 “testemail@leetcode.com” 和 “testemail@lee.tcode.com”。
思路:用 split 把本地名和域名分开,然后来处理这两种情况很容易的多,一个对应 continue,一个对应 break
class Solution(object):
def numUniqueEmails(self, emails):
"""
:type emails: List[str]
:rtype: int
"""
result = []
local_domain = [] #split 存放本地名和域名
for item in emails:# 遍历每封邮件
local_domain = list(item.split("@"))
local = ""
for s in local_domain[0]:# 遍历本地名
if s==".": # 跳过 .
continue
elif s=="+": # 遇到+,后面都没有了
break
else:
local+=s # 把本地名拼起来
result.append(local+"@"+local_domain[1]) # 本地名和域名都拼起来
return len(set(result)) # 返回集合的长度
811. 子域名访问计数(split)
父域名"leetcode.com"以及顶级域名 “com”。
给定一个带访问次数和域名的组合,要求分别计算每个域名被访问的次数。其格式为访问次数+空格+地址,例如:“9001 discuss.leetcode.com”。
接下来会给出一组访问次数和域名组合的列表cpdomains 。要求解析出所有域名的访问次数,输出格式和输入格式相同,不限定先后顺序。
-
示例 1:
输入:
[“9001 discuss.leetcode.com”]
输出:
[“9001 discuss.leetcode.com”, “9001 leetcode.com”, “9001 com”] -
说明:
例子中仅包含一个网站域名:“discuss.leetcode.com”。按照前文假设,子域名"leetcode.com"和"com"都会被访问,所以它们都被访问了9001次。
思路:用字典,key 为 域名,value 为访问次数,如果 key 存在字典中,就把 value 加起来,最后再把字典组合一下,输出成题目要求的方式!
class Solution(object):
def subdomainVisits(self, cpdomains):
"""
:type cpdomains: List[str]
:rtype: List[str]
"""
result = {} # 字典,key 为域名, value 为访问次数
for item in cpdomains: # 遍历每条访问信息
num_domain = list(item.split(" ")) # 访问次数和域名分开
dot_domain = list(num_domain[1].split(".")) # 域名根据 . 分开
if dot_domain[-1] in result: # 判断域名是否重复出现
result[dot_domain[-1]] += int(num_domain[0])
print("hello")
else:
result[dot_domain[-1]] = int(num_domain[0])
if dot_domain[-2]+"."+dot_domain[-1] in result:# 判断域名是否重复出现
result[dot_domain[-2]+"."+dot_domain[-1]] += int(num_domain[0])
else:
result[dot_domain[-2]+"."+dot_domain[-1]] = int(num_domain[0])
if len(dot_domain) == 3: # 域名为两个点的情况
if dot_domain[-3]+"."+dot_domain[-2]+"."+dot_domain[-1] in result:# 判断域名是否重复出现
result[dot_domain[-3]+"."+dot_domain[-2]+"."+dot_domain[-1]] += int(num_domain[0])
else:
result[dot_domain[-3]+"."+dot_domain[-2]+"."+dot_domain[-1]] = int(num_domain[0])
result_list = [] # 把字典转化为列表,输出结果
for i in result:
result_list.append(str(result[i])+" "+i)
return result_list
58. 最后一个单词的长度
法一:遍历
class Solution(object):
def lengthOfLastWord(self, s):
"""
:type s: str
:rtype: int
"""
result_tmp = 0
result = 0
for index in range(len(s)):
if s[index] == " ":
result_tmp = 0
else:
result_tmp += 1
result = result_tmp
return result
法二:利用 strip 和 split
class Solution(object):
def lengthOfLastWord(self, s):
"""
:type s: str
:rtype: int
"""
return len(s.strip(" ").split(" ")[-1])
821. 字符的最短距离
给定一个字符串 S 和一个字符 C。返回一个代表字符串 S 中每个字符到字符串 S 中的字符 C 的最短距离的数组。
-
示例 1:
输入: S = “loveleetcode”, C = ‘e’
输出: [3, 2, 1, 0, 1, 0, 0, 1, 2, 2, 1, 0] -
说明:
字符串 S 的长度范围为 [1, 10000]。
C 是一个单字符,且保证是字符串 S 里的字符。
S 和 C 中的所有字母均为小写字母。
思路:暴力法,找到所有 C 的位置,遍历 S,保留每个字母到 C 的最短距离!也可以从 C 开始,向左向右便利找到 S 的字母!
class Solution(object):
def shortestToChar(self, S, C):
"""
:type S: str
:type C: str
:rtype: List[int]
"""
C_position = [] # 记录所以 C 的位置
for position in range(len(S)):
if S[position] == C:
C_position.append(position)
result = []
# result
for i in range(len(S)):
diff = [] # 记录字母与所有 C 的差值
min_diff = len(S)
for j in C_position:
min_diff = min(min_diff,abs(i-j)) # 求出来最小的差值
result.append(min_diff)
return result
xxx. 同构字符串
给定两个字符串 s 和 t,判断它们是否是同构的
如果 s 中的字符可以被替换得到 t ,那么这两个字符串是同构的
所有出现的字符都必须用另一个字符替换,同时保留字符的顺序。两个字符不能映射到同一个字符上,但字符可以映射自己本身
输入两个字符串,分号隔开
输出 true or false
eg
输入
‘aab;ccd’
输出
True
n = input().split(";")
strA = n[0]
strB = n[1]
print(len(set(strA))==len(set(strB))==len(set(zip(strA,strB))))
哈哈,这就是 python 的魔力
1221. 分割平衡字符串
在一个「平衡字符串」中,‘L’ 和 ‘R’ 字符的数量是相同的。
给出一个平衡字符串 s,请你将它分割成尽可能多的平衡字符串。
返回可以通过分割得到的平衡字符串的最大数量。
-
示例 1:
输入:s = “RLRRLLRLRL”
输出:4
解释:s 可以分割为 “RL”, “RRLL”, “RL”, “RL”, 每个子字符串中都包含相同数量的 ‘L’ 和 ‘R’。 -
示例 2:
输入:s = “RLLLLRRRLR”
输出:3
解释:s 可以分割为 “RL”, “LLLRRR”, “LR”, 每个子字符串中都包含相同数量的 ‘L’ 和 ‘R’。 -
示例 3:
输入:s = “LLLLRRRR”
输出:1
解释:s 只能保持原样 “LLLLRRRR”.
思路:给出的例子有一些误导性,好像是数连续的 L 和 R 出现相等个数的次数,我一开始是用下标配合 while 循环来跳重复出现的相等字符!后面这个示例出错了 "RLRRRLLRLL"
,改进思路,出现 R 就 +1,出现 L 就 -1,等于零的话结果 +1
class Solution(object):
def balancedStringSplit(self, s):
"""
:type s: str
:rtype: int
"""
result = 0
total = 0
for i in s:
if i == "L":
total -= 1
elif i == "R":
total += 1
if total == 0:
result += 1
return result
1021. 删除最外层的括号
有效括号字符串为空 (“”)、“(” + A + “)” 或 A + B,其中 A 和 B 都是有效的括号字符串,+ 代表字符串的连接。例如,“”,“()”,“(())()” 和 “(()(()))” 都是有效的括号字符串。
如果有效字符串 S 非空,且不存在将其拆分为 S = A+B 的方法,我们称其为原语(primitive),其中 A 和 B 都是非空有效括号字符串。
给出一个非空有效字符串 S,考虑将其进行原语化分解,使得:S = P_1 + P_2 + … + P_k,其中 P_i 是有效括号字符串原语。
对 S 进行原语化分解,删除分解中每个原语字符串的最外层括号,返回 S 。
- 示例 1:
输入:“(()())(())”
输出:“()()()”
解释:
输入字符串为 “(()())(())”,原语化分解得到 “(()())” + “(())”,
删除每个部分中的最外层括号后得到 “()()” + “()” = “()()()”。
思路:用栈,左括号进栈,右括号出站,进栈后,如果栈内元素大于1,就是内层括号,出栈后,如果栈内元素大于等于1,表示内层括号!
class Solution(object):
def removeOuterParentheses(self, S):
"""
:type S: str
:rtype: str
"""
astack = []
count = 0
result = ""
for i in S:
if i == "(":
astack.append(i)
count+=1
if count >1:
result+=i
elif i == ")":
astack.pop()
count-=1
if count >=1:
result+=i
return result
784. 字母大小写全排列
给定一个字符串S,通过将字符串S中的每个字母转变大小写,我们可以获得一个新的字符串。返回所有可能得到的字符串集合。
示例:
输入: S = “a1b2”
输出: [“a1b2”, “a1B2”, “A1b2”, “A1B2”]
输入: S = “3z4”
输出: [“3z4”, “3Z4”]
输入: S = “12345”
输出: [“12345”]
思路:n 个字母就会有 2 n 2^n 2n 个结果,我想到的时候用 2 n 2^n 2n 的二进制来修改对应位置的元素,0不修改,1修改
class Solution(object):
def letterCasePermutation(self, S):
"""
:type S: str
:rtype: List[str]
"""
count = 0 # 记录字母的个数
index = [] # 记录字母出现的下标
# 统计字母的个数和下标
for i in range(len(S)):
if "a"<=S[i]<="z" or "A"<=S[i]<="Z":
count +=1
index.append(i)
# count 个字母,结果就会有 2**count 个
result = [S]*2**count
# 用二进制的思想,遍历0-2**count的二进制,0不改变字母,1改变字母
for i in range(2**count): # 遍历来修改每一种结果
x = bin(i)[2:].zfill(count) # 二进制,记得去掉前缀和补0
for j in range(count): # 遍历每一个要修改的位置
if x[j] == "1": # 0不改变字母,1改变字母
if "a"<=result[i][index[j]]<="z": # 小写 - 32,注意从字符串中改变一个字符的方法
if index[j] == len(S)-1: # 如果字母最后一个元素,就不要加后面的数字了
result[i] = result[i][:index[j]]+chr(ord(result[i][index[j]])-32)
else:
result[i] = result[i][:index[j]] + chr(ord(result[i][index[j]]) - 32) + result[i][index[j] + 1:]
elif "A" <= result[i][index[j]] <= "Z": # 大写 + 32,注意从字符串中改变一个字符的方法
if index[j] == len(S)-1: # 如果字母最后一个元素,就不要加后面的数字了
result[i] = result[i][:index[j]] + chr(ord(result[i][index[j]]) + 32)
else:
result[i] = result[i][:index[j]] + chr(ord(result[i][index[j]])+32) + result[i][index[j] + 1:]
return result
14. 最长公共前缀
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 “”。
- 示例 1:
输入: [“flower”,“flow”,“flight”]
输出: “fl”
思路:可以利用 zip(*list)
来访问 list
中每项的同一个位置,相等(利用集合的长度是否为1来判断),结果就加上这个字母,不相等,就跳出
class Solution(object):
def longestCommonPrefix(self, strs):
"""
:type strs: List[str]
:rtype: str
"""
result = ""
for i in zip(*strs): # i 是元组, 由 strs 每项的第 n 个元素组成
if len(set(i)) == 1: # 判断元素是否一致
result += i[0]
else:
break
return result
1323. 6 和 9 组成的最大数字
给你一个仅由数字 6 和 9 组成的正整数 num。
你最多只能翻转一位数字,将 6 变成 9,或者把 9 变成 6 。
请返回你可以得到的最大数字。
示例 1:
输入:num = 9669
输出:9969
解释:
改变第一位数字可以得到 6669 。
改变第二位数字可以得到 9969 。
改变第三位数字可以得到 9699 。
改变第四位数字可以得到 9666 。
其中最大的数字是 9969 。
示例 2:
输入:num = 9996
输出:9999
解释:将最后一位从 6 变到 9,其结果 9999 是最大的数。
示例 3:
输入:num = 9999
输出:9999
解释:无需改变就已经是最大的数字了。
提示:
1 <= num <= 10^4
num 每一位上的数字都是 6 或者 9 。
字符串的灵活运用
num = str(num)
for i in range(len(num)):
if num[i] == "6":
num = num[:i] + "9" + num[i+1:]
break
return int(num)
replace 的灵活运用
return str(num).replace("6","9",1)
28. 找出字符串中第一个匹配项的下标
法一:有效的利用 index 特性
class Solution(object):
def strStr(self, haystack, needle):
"""
:type haystack: str
:type needle: str
:rtype: int
"""
if needle not in haystack:
return -1
else:
return haystack.index(needle)
法二:切片
class Solution(object):
def strStr(self, haystack, needle):
"""
:type haystack: str
:type needle: str
:rtype: int
"""
if needle not in haystack:
return -1
lh = len(haystack)
l = len(needle)
if lh == l:
return 0
for i in range(lh - l+1):
if haystack[i:i+l] == needle:
return i
法三:KMP 算法