你的位置:首页 > 信息动态 > 新闻中心
信息动态
联系我们

【春招冲刺班-7天刷题挑战】(三)

2021/10/19 1:01:33

目录

十七、LC 60. 排列序列

17.1 题求

17.2 求解

十八、LC 22. 括号生成

18.1 题求

18.2 求解

十九、LC 753. 破解保险箱

19.1 题求

19.2 求解


十七、LC 60. 排列序列

17.1 题求

17.2 求解

法一:迭代

# 28ms - 94.54%
class Solution:
    def getPermutation(self, n: int, k: int) -> str:
        from functools import reduce
        kinds = reduce(lambda x, y: x*y, range(1, n+1))  # 阶乘 / 当前数组 arr 可构成的不同排列总数

        res = []  # 结果列表
        arr = [str(i) for i in range(1, n+1)]  # 当前可选数字数组 arr

        while len(res) < n:
            kinds //= len(arr)        # 在当前数组 arr 中, 以每个数字开头的不同排列数
            idx = (k-1) // kinds      # arr 的所有排列中, 第 idx 个数字即为第 k 大排列的首位数字
            res.append(arr.pop(idx))  # 将第 idx 个数字移出 arr 并加入结果列表
            k -= (idx + 1) * kinds    # 更新/对齐 k, 令下一个首位数字在剩余 arr 的所有排列中为第 k 大
     
        return ''.join(res)

参考资料:

力扣


十八、LC 22. 括号生成

18.1 题求

18.2 求解

法一:回溯

# 84ms - 6.92%
class Solution:
    def generateParenthesis(self, n: int) -> List[str]:

        # 设 n=3 种, 则首个必然是 "(" , 末尾必是 ")" 于是剩余左半边只可能有 "((", "()", ")(", "))"
        # 显然 "))" 非法, 故可能的左半边只有 "(((", "(()", "()(" 开始回溯并记录所有有效组合
        
        res = []
        num = n * 2
        choice = {'(', ')'}
        
        def check(arr):
            flag = 0
            for i in arr:
                flag += 1 if i == '(' else -1
                # ')' 不可以在任何时候比 '(' 多
                if flag < 0:
                    return False
            # '('也不可以比 ')' 多
            return flag == 0

        def recur(arr):
            # 检查
            if len(arr) == num:
                if check(arr):
                    res.append(''.join(arr))
                return
            
            # 回溯
            for j in choice:
                arr.append(j)
                recur(arr)
                arr.pop()       
            
        recur(['('])
        return res

法一改:回溯 + 剪枝 + 有效性检查函数

# 40ms - 38.81%
class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        if n == 1:
            return ["()"]
        
        res = []
        num = n * 2 - 1  # 总数 - 1
        choice = {'(', ')'}
        
        def check(arr, half=False):
            flag = 0
            for i in arr:
                flag += 1 if i == '(' else -1
                # ')' 不可以在任何时候比 '(' 多
                if flag < 0:
                    return False
            # '('也不可以比 ')' 多
            return True if half else flag == 0  

        def recur(arr):
            # 半路检查 - 半数时必须满足 num('(') >= num(')') - 相当于剪枝
            if len(arr) == n:
                if not check(arr, half=True):
                    return
            
            # 完整检查
            elif len(arr) == num:
                arr.append(')')  # 强制约束最后必为 ')' - 相当于剪枝
                if check(arr):
                    res.append(''.join(arr))
                arr.pop()  # 及时弹出避免影响后续回溯 (Python list 是 mutable 的)
                return
            
            # 回溯
            for j in choice:
                arr.append(j)
                recur(arr)
                arr.pop()  # 及时弹出避免影响后续回溯 (Python list 是 mutable 的)        
            
        # 强制约束首个必为 ')' - 相当于剪枝
        recur(['('])
        return res

法一再改:回溯 + 剪枝 + 有效性计数器 (取代检查函数)

# 36ms - 59.80%
class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        res = []
        num = n * 2 - 1  # 总数 - 1
        choice = {('(', 1), (')', -1)}  # type, score

        def recur(arr, cnt):
            # 任何时候总有 num('(') >= num(')') - 相当于剪枝
            if cnt < 0:
                return
            
            # 完整检查
            if len(arr) == num:
                arr.append(')')  # 强制约束最后必为 ')' - 相当于剪枝
                if cnt == 1:
                    res.append(''.join(arr))
                arr.pop()  # 及时弹出避免影响后续回溯 (Python list 是 mutable 的)
                return
            
            # 回溯
            for j, k in choice:
                arr.append(j)
                recur(arr, cnt+k)
                arr.pop()  # 及时弹出避免影响后续回溯 (Python list 是 mutable 的)        

        recur(['('], 1)  # 强制约束首个必为 ')' - 相当于剪枝
        return res

官方说明 

# 128ms - 5.04%
class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        def generate(A):
            if len(A) == 2*n:
                if valid(A):
                    ans.append("".join(A))
            else:
                A.append('(')
                generate(A)
                A.pop()
                A.append(')')
                generate(A)
                A.pop()

        def valid(A):
            bal = 0
            for c in A:
                if c == '(': 
                    bal += 1
                else: 
                    bal -= 1
                if bal < 0: 
                    return False
            return bal == 0

        ans = []
        generate([])
        return ans

# 40ms - 38.81%
class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        ans = []
        def backtrack(S, left, right):
            if len(S) == 2 * n:
                ans.append(''.join(S))
                return
            if left < n:
                S.append('(')
                backtrack(S, left+1, right)
                S.pop()
            if right < left:
                S.append(')')
                backtrack(S, left, right+1)
                S.pop()

        backtrack([], 0, 0)
        return ans

# 20ms - 99.76% - 自底向上递归
class Solution:
    @lru_cache(None)
    def generateParenthesis(self, n: int) -> List[str]:
        if n == 0:
            return ['']
        res = []
        for p in range(n):
            for left in self.generateParenthesis(p):
                for right in self.generateParenthesis(n-1-p):
                    res.append(f'({left}){right}')
        # n 组括号的所有组合
        return res

动态规划

# 24ms - 98.28%
class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        #  dp[i] 表示 i 组括号的所有有效组合
        #  dp[i] = "(dp[p] 的所有有效组合)+【dp[q]的组合】"
        #          其中  p 从 0 遍历到 i-1, 同时 q 则相应从 i-1 到 0, 始终满足 p+q = i-1
        
        dp = [[] for _ in range(n+1)]  # dp[i] 存放 i 组括号的所有有效组合
        dp[0].append("")               # 初始化 dp[0], 共有 0 组括号时没有组合
        dp[1].append("()")             # 初始化 dp[1], 共有 0 组括号时组合唯一
        
        # 计算 dp[i], 即共有 i 组括号时的所有组合, 从第 2 组开始
        for i in range(2, n+1):        
            for p in range(i):         # 遍历 p, 范围 [0, i]
                lst1 = dp[p]           # 得到 dp[p] 的所有有效组合
                lst2 = dp[i-1-p]       # 得到 dp[q] = dp[(i-1)-p] 的所有有效组合
                
                # 遍历各组合插入到当前1组 () 的中、右侧
                for k1 in lst1:
                    for k2 in lst2:
                        # "(" + 【i=p时所有括号的排列组合】+ ")" +【i=q时所有括号的排列组合】
                        # p+q = n-1, 即除了 () 外剩下的 n-1 组
                        dp[i].append(f"({k1}){k2}")  # 各 n 组合 "(" + k1+ ")" + k2
        return dp[n]

参考资料:

力扣

力扣

力扣


十九、</> 数组组成最大数

19.1 题求

19.2 求解

法一:自定义列表排序比较规则

# 12ms - 100%
from functools import cmp_to_key
# functools 中的 cmp_to_key 可将一个 cmp 函数变成一个 key 函数, 从而支持自定义排序
def compare(x, y):
    # 当 x > y 时返回 1, x = y 时返回 0, 否则返回 -1
    # 它在 list 中的工作机制即对元素两两比较, cmp 返回正数时交换两元素
    return int(y+x) - int(x+y)  

arr = input()[1:-1].split(',')
arr = sorted(arr, key=cmp_to_key(compare))
print(''.join(arr))
# 12ms - 100%
from functools import cmp_to_key
# functools 中的 cmp_to_key 可将一个 cmp 函数变成一个 key 函数, 从而支持自定义排序
arr = input()[1:-1].split(',')
arr.sort(key = cmp_to_key(lambda x, y: int(y+x) - int(x+y)))
print(''.join(arr))

网友实现

# 12ms - 100.00%
class myStr(str):
    def __init__(self, s):
        self.data = s
    def __lt__(self, s):
        return self.data + s < s + self.data

def comb():
    line = input().strip()[1:-1].split(',')
    arr = map(myStr, line)
    res = sorted(arr, reverse=True)
    return "".join(res)
        
if __name__ == "__main__":
    print(comb())

参考资料:

力扣