【python】Leetcode(primer-set)

文章介绍了LeetCode中的几个与集合操作相关的题目,包括求不含重复元素数组的子集、允许重复元素数组的子集、匹配子序列的单词数、键盘行上的单词和最长回文串的生成。解决方案涉及迭代、回溯和数据结构优化。
摘要由CSDN通过智能技术生成

在这里插入图片描述

更多 leetcode 题解可参考:【Programming】


78. 子集(集合的所有子集)

给定一组不含重复元素的整数数组 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. 找出所有子集的异或总和再求和


90. 子集 II(集合的所有子集)

给定一个可能包含重复元素的整数数组 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

792. 匹配子序列的单词数(判断是否为子集)

给定字符串 S 和单词字典 words, 求 words[i] 中是 S 的子序列的单词个数。

  • 示例:
    输入:
    S = “abcde”
    words = [“a”, “bb”, “acd”, “ace”]
    输出: 3
    解释: 有三个是 S 的子序列的单词: “a”, “acd”, “ace”。
    注意:

所有在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])

500. 键盘行(集合的交集)

给定一个单词列表,只返回可以使用在键盘同一行的字母打印出来的单词。键盘如下图所示。

在这里插入图片描述

  • 示例:
    输入: [“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

在这里插入图片描述

拓展,集合的并集 | 集合的差 -


409. 最长回文串(set)

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

在构造过程中,请注意区分大小写。比如 “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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值