【力扣python】1239. 串联字符串的最大长度

1239. 串联字符串的最大长度
在这里插入图片描述

写法一

官方方法,利用位运算,删除一些内部有重复字母的串,再递归遍历所有情况

class Solution:
    def maxLength(self, arr: List[str]) -> int:
        masks = []
        for per in arr:
            mask = 0
            for ch in per:
                index = ord(ch) - ord("a")
                if((mask >> index) & 1): # 表示有重复的字母了
                    mask = 0
                    break
                mask |= (1 << index)
            if mask > 0: # 表示该串不含重复字母
                masks.append(mask)
        
        ans = 0
        def backtrack(pos: int, mask: int) -> None:
            if pos == len(masks): # 已经到了最后一层
                nonlocal ans # 标识该变量是上一级函数中的局部变量
                ans = max(ans, bin(mask).count("1")) # 数其二进制中有多少个1
                return
            
            if (mask & masks[pos]) == 0:   # mask 和 masks[pos] 无公共元素,其实这种判断算是一种剪枝
                backtrack(pos + 1, mask | masks[pos])
            # 还是需要试试不加的情况
            backtrack(pos + 1, mask)
        
        backtrack(0, 0)
        return ans

写法二

本人利用set替代检查重复的操作,实测时间消耗更少

class Solution:
    def maxLength(self, arr: List[str]) -> int:
        masks = []
        for per in arr:
            mask = 0
            for ch in per:
                mask |= (1 << (ord(ch) - ord("a")))
            if len(per) == len(set(per)):
                masks.append(mask)
        
        ans = 0
        def backtrack(pos: int, mask: int) -> None:
            if pos == len(masks): # 已经到了最后一层
                nonlocal ans # 标识该变量是上一级函数中的局部变量
                ans = max(ans, bin(mask).count("1")) # 数其二进制中有多少个1
                return
            
            if (mask & masks[pos]) == 0:   # mask 和 masks[pos] 无公共元素,其实这种判断算是一种剪枝
                backtrack(pos + 1, mask | masks[pos])
            # 还是需要试试不加的情况
            backtrack(pos + 1, mask)
        
        backtrack(0, 0)
        return ans

写法三

官方方法,将上面的递归转化为迭代,减少时间消耗,增加空间消耗

class Solution:
    def maxLength(self, arr: List[str]) -> int:
        masks = [0] # 初始化一个没加任何串的情况
        ans = 0
        for per in arr:
            if len(per) != len(set(per)):
                continue
            mask = 0
            for ch in per:
                mask |= (1 << (ord(ch) - ord("a")))

            for i in range(len(masks)):
                m = masks[i]
                if m & mask == 0: # 无公共元素
                    masks.append(m | mask)
                    ans = max(ans, bin(masks[-1]).count("1"))
        return ans

写法四

参考其他人的方法,使用动规方法

class Solution:
    def overlap(self, s1, s2):
        return len(s1+s2) != len(set(s1+s2))

    def self_overlap(self, s):
        return len(s) != len(set(s))

    def max_substring(self, arr) -> str:
        len_ = len(arr)
        dp = [""]*(len_+1)

        for i in range(1, len_+1):
            if self.self_overlap(arr[i-1]): # 第i个串自己有重复
                dp[i] = dp[i-1]
            elif not self.overlap(dp[i-1], arr[i-1]): # 第i个串和前面的最长串无交集
                dp[i] = dp[i-1] + arr[i-1]
            else:
                # 第i个串和前面的最长串无交集
                no_arr_i = []
                for j in range(1, i):
                    if not self.overlap(arr[j-1], arr[i-1]): # 把前i个(不含i)所有和第i个串无交集的取出来
                        no_arr_i.append(arr[j-1])
                # 单独计算这些串中最长的可行解,并加上第i个串
                max_arr_i = arr[i-1] if len(no_arr_i) == 0 else self.max_substring(no_arr_i)+arr[i-1]
                # 如果比不加第i个串的情况更好,则加上
                dp[i] = max_arr_i if len(max_arr_i) > len(dp[i-1]) else dp[i-1]
        return dp[len_]

    def maxLength(self, arr: List[str]) -> int:  
        return len(self.max_substring(arr))

写法五

进行本人最擅长的空间优化,至此代码较为精简美观

class Solution:
    def max_substring(self, arr) -> str:
        dp = ""
        for i, s in enumerate(arr):
            if len(s) != len(set(s)): # 第i个串自己有重复
                continue
            elif len(dp+s) == len(set(dp+s)): # 第i个串和前面的最长串无交集
                dp += s
            else: # 第i个串和前面的最长串无交集
                # 把前i个(不含i)所有和第i个串无交集的取出来
                no_arr_i = [arr[j] for j in range(i) if len(arr[j]+s) == len(set(arr[j]+s))]
                # 单独计算这些串中最长的可行解,并加上第i个串
                max_arr_i = s if len(no_arr_i) == 0 else self.max_substring(no_arr_i)+s
                # 如果比不加第i个串的情况更好,则加上
                dp = max_arr_i if len(max_arr_i) > len(dp) else dp
        return dp

    def maxLength(self, arr: List[str]) -> int:  
        return len(self.max_substring(arr))
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值