力扣python1239. 串联字符串的最大长度

Posted _less is more

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了力扣python1239. 串联字符串的最大长度相关的知识,希望对你有一定的参考价值。

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))

以上是关于力扣python1239. 串联字符串的最大长度的主要内容,如果未能解决你的问题,请参考以下文章

[M暴搜] lc1239. 串联字符串的最大长度(dfs暴搜+状态压缩+二进制枚举+思维)

LeetCode 1239串联字符串的最大长度[递归 哈希压缩] HERODING的LeetCode之路

LeetCode 483. 最小好进制(数学) / 1239. 串联字符串的最大长度 / 1600. 皇位继承顺序(多叉树) / 401. 二进制手表

力扣:串联所有单词的子串(滑动窗口+哈希)

2021/6/19 刷题笔记串联字符串的最大长度与回溯法

串联字符串的最大长度(位运算)