更多 leetcode 题解可参考:【Programming】
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集
思路:可以迭代,可以回溯,
算 1 的子集的时候,新增 1 结合 空集;
算 2 的子集的时候,2 结合 1 的所有子集;
算 3 的子集的时候,3 结合 2 的所有子集
…
class Solution(object):
def subsets(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
result = [[]]
for i in nums:
result.extend([j + [i] for j in result])
return result
相似题目 1863. 找出所有子集的异或总和再求和
给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
思路:和 78 唯一不同的是 nums 可能包含一样的元素,这个时候就会存在 [1,2] 和 [2,1] 或者更难一点的 [1,2,2] 和 [2,1,2] 的情况,78 的解法这两个都会保留(78中元素不一样),但是这题只能保留其中一种!
简单的 set 好像排除不了,我用的是 sorted
class Solution(object):
def subsetsWithDup(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
result = [[]]
for i in nums:
result.extend([j + [i] for j in result])
set1 = set(tuple(sorted(item)) for item in result)
# tuple 才能 hash——set,sorted 配合set来去重
list1 = list(list(item) for item in set1)
# 转化成输出的格式
return list1
给定字符串 S 和单词字典 words, 求 words[i] 中是 S 的子序列的单词个数。
所有在words和 S 里的单词都只由小写字母组成。
S 的长度在 [1, 50000]。
words 的长度在 [1, 5000]。
words[i]的长度在[1, 50]。
思路:in 或者 find 都不能判断这种跨越的子集,暴力法遍历了
class Solution(object):
def numMatchingSubseq(self, S, words):
"""
:type S: str
:type words: List[str]
:rtype: int
"""
count = 0
for item in words:
i = 0
j = 0
flag = 0
while(i<len(S) and j<len(item)):
if S[i] == item[j]:
i+=1
j+=1
if j==len(item):
break
else:
i+=1
if i>len(item) and item[j] not in S: # 根本不在S中就不浪费表情去一个一个滑动找了
break
if j == len(item):
count+=1
return count
但是超时了!字典树!
class Solution(object):
def numMatchingSubseq(self, S, words):
"""
:type S: str
:type words: List[str]
:rtype: int
"""
import collections
waiting = collections.defaultdict(list)
for w in words:
waiting[w[0]].append(iter(w[1:]))
for c in S:
# print('c', c)
# Python 字典 pop() 方法删除字典给定键 key 所对应的值,返回值为被删除的值。key值必须给出。 否则,返回default值。
# 把所有以c开头的word都删除
for it in waiting.pop(c, ()):
# 如果这个word还有其他字母,则与之前的合并,否则放到None中,表示该word能匹配
waiting[next(it, None)].append(it)
return len(waiting[None])
给定一个单词列表,只返回可以使用在键盘同一行的字母打印出来的单词。键盘如下图所示。
示例:
输入: [“Hello”, “Alaska”, “Dad”, “Peace”]
输出: [“Alaska”, “Dad”]
注意:
你可以重复使用键盘上同一字符。
你可以假设输入的字符串将只包含字母。
思路:暴力法,比较每一个字母是否在键盘的三行中
class Solution(object):
def findWords(self, words):
"""
:type words: List[str]
:rtype: List[str]
"""
s1 = "qwertyuiop"
s2 = "asdfghjkl"
s3 = "zxcvbnm"
result = []
for word in words: # 遍历单词
item = set(word.lower())
num1 = 0
num2 = 0
num3 = 0
for i in item:
if i in s1:
num1+=1
elif i in s2:
num2+=1
else:
num3+=1
if num1==len(item) or num2==len(item) or num3==len(item):
result.append(word)
return result
还可以用集合的交集(和三行的交集是否为本身,是的话就表示该 string 是由一行键盘打出来的),这样就不用两层循环了!
class Solution(object):
def findWords(self, words):
"""
:type words: List[str]
:rtype: List[str]
"""
s1 = "qwertyuiop"
s2 = "asdfghjkl"
s3 = "zxcvbnm"
result = []
for word in words: # 遍历单词
if set(word.lower()) & set(s1) == set(word.lower()) or\
set(word.lower()) & set(s2) == set(word.lower()) or \
set(word.lower()) & set(s3) == set(word.lower()):
result.append(word)
return result
拓展,集合的并集 | 集合的差 -
给定一个包含大写字母和小写字母的字符串,找到通过这些字母构造成的最长的回文串。
在构造过程中,请注意区分大小写。比如 “Aa” 不能当做一个回文字符串。
注意:
假设字符串的长度不会超过 1010。
示例 1:
输入:
“abccccdd”
输出:
7
解释:
我们可以构造的最长的回文串是"dccaccd", 它的长度是 7。
思路:先用 set 统计每个元素的数量,偶数的可以直接算作回文串的子集,奇数减1成偶数让其构成回文串子集(如果元素数量是1,减去后就为0)!最后输出结果,把子集拼起来,+1 即可,如果子集拼起来的长度和原字符串的长度相等,就不用加1了!
class Solution(object):
def longestPalindrome(self, s):
"""
:type s: str
:rtype: int
"""
set1 = set(s)
number_list = []
sum1 = 0
for i in set1: # 统计每个元素的数量
number_list.append(s.count(i))
for i,j in enumerate(number_list): # 遍历数量,偶数不变,奇数减一
if j % 2 == 1:
number_list[i] -= 1
sum1 += number_list[i]
if sum1+1 > len(s): # 这里避免,bb 的情况
return len(s)
else:
return sum1+1