备战菊厂笔试4

目录

39.组合总和

回溯(单向剪枝)

3102.最小化曼哈顿距离

利用曼哈顿距离的性质

3163.压缩字符串3

46.全排列

53.最大子数组和


39.组合总和

39. 组合总和

注意:

set不能添加list得加元组

元组不可修改

sorted后得赋值

python 复制代码
class Solution:
    def combinationSum(self, candidates,target):

        ans=set()
        def fenjie(num,se):
            if num==0:
                se=tuple(sorted(se))
                ans.add(se)
                return
            if num<0:
                return
            
            for i in candidates:
                se2=tuple(list(se)+[i])
                fenjie(num-i,se2)

        fenjie(target,())
        return [list(x) for x in ans]  # 转换为题目要求的格式
if __name__=='__main__':
    candidates = [2,3,6,7];target = 7

    sol=Solution()
    ans=sol.combinationSum(candidates,target)
    print(ans)

虽然过了,但这道题更好的办法是

回溯(单向剪枝)

回溯是一种 试探+撤销 的策略

我们将这问题看成一颗搜索树,每个节点表示一种选择路径,那么我们从根节点开始一步步试探性地往下走,直到走到满足条件的叶子节点 ,那么就把路径加入答案

我们用start控制开始下标,单向(升序)地往后面选(注意同一个数字可以重复使用,那么下一层就是从当前start开始

python 复制代码
start=0, path=[], remaining=7
├── 选2 → path=[2], remaining=5
│   ├── 选2 → path=[2,2], remaining=3
│   │   ├── 选2 → path=[2,2,2], remaining=1
│   │   │   └── 选2 → path=[2,2,2,2], remaining=-1 ❌ 超了,返回
│   │   │   └── 选3 → path=[2,2,2,3], remaining=-2 ❌ 超了,返回
│   │   ├── 选3 → path=[2,2,3], remaining=0 ✅ 找到结果
│   │   └── ...
│   └── 选3 → path=[2,3], remaining=2
├── 选3 → path=[3], remaining=4
│   ├── 选3 → path=[3,3], remaining=1
│   └── ...
├── 选6 → path=[6], remaining=1
├── 选7 → path=[7], remaining=0 ✅ 找到结果
python 复制代码
class Solution:
    def combinationSum(self, candidates, target):
        res = []
        candidates.sort()

        def backtrack(start, path, remaining):
            if remaining == 0:
                res.append(path[:])  # 找到一个合法组合,加入结果
                return
            if remaining < 0:
                return  # 超过了目标值,剪枝

            for i in range(start, len(candidates)):
                path.append(candidates[i])
                backtrack(i, path, remaining - candidates[i])  # 可重复选,从 i 开始
                path.pop()  # 撤销上一步选择,继续尝试下一个
                
        backtrack(0, [], target)
        return res

其中 path,pop() 有点像 恢复vis[ ] = 0

3102.最小化曼哈顿距离

3102. 最小化曼哈顿距离

本来我想用一半的二维矩阵来优化空间复杂度,但是这样反而得不偿失了,太绕了 连正确答案都跑不出来,还是正常用二维的

这题的主要思路的思路就是枚举删的点,然后再枚举所有点的所有边(除去当时删的点的),进行表示

python 复制代码
'''
class Solution:
    def minimumDistance(self, points):
        n=len(points)
        ma=[[0]*i for i in range(n-1,0,-1)]
        for i in range(n-1):
            for j in range(i+1,n):
                dis=abs(points[i][0]-points[j][0])+abs(points[i][1]-points[j][1])
                ma[i][j-i-1]=dis
        print(ma)

        ans=float('inf')
        for i in range(n):#去掉的点
            now=-1
            for j in range(n):#除去掉的点外的点出发到其他点的距离
                if j==i:
                    continue
                else:
                    for a in range(n-j-1):
                        if a+1==i:continue
                        now=max(now,ma[j][a])
                    for b in range(j):
                        if b==i:continue
                        now=max(now,ma[b][j-b-1])
                    ans=min(ans,now)
        return ans
'''
class Solution:
    def minimumDistance(self, points):
        import itertools
        n = len(points)
        ans = float('inf')
        for skip in range(n):  # 枚举删除哪一个点
            max_dist = 0
            remaining = [points[i] for i in range(n) if i != skip]
            for i in range(len(remaining)):
                for j in range(i + 1, len(remaining)):
                    x1, y1 = remaining[i]
                    x2, y2 = remaining[j]
                    dist = abs(x1 - x2) + abs(y1 - y2)
                    max_dist = max(max_dist, dist)
            ans = min(ans, max_dist)
        return ans
if __name__=='__main__':
    points=[[3,10],[5,15],[10,2],[4,4]]

    sol=Solution()
    ans=sol.minimumDistance(points)
    print(ans)
        

但是这样暴力肯定会TLE

利用曼哈顿距离的性质

python 复制代码
class Solution:
    def minimumDistance(self, points):
        n = len(points)
        vals = [[] for _ in range(4)]  # 保存四种变换

        for i, (x, y) in enumerate(points):
            vals[0].append((x + y, i))
            vals[1].append((x - y, i))
            vals[2].append((-x + y, i))
            vals[3].append((-x - y, i))

        candidates = set()
        for arr in vals:
            arr.sort()
            candidates.add(arr[0][1])     # 最小值对应点
            candidates.add(arr[-1][1])    # 最大值对应点

        def get_max_dist(skip):
            max_val = 0
            for arr in vals:
                temp = [(val, idx) for val, idx in arr if idx != skip]
                max_val = max(max_val, temp[-1][0] - temp[0][0])
            return max_val

        return min(get_max_dist(i) for i in candidates)

3163.压缩字符串3

3163. 压缩字符串 III

主要用到 strip

python 复制代码
class Solution:
    def compressedString(self, word: str) -> str:
        comp=''
        l=len(word)
        while word:
            '''
            i=0
            while word[i]==word[i+1]:#前缀
                i+=1
            comp+=str(i+1)+word[i]
            '''
            c=word[0]
            
            word=word.lstrip(c)# lstrip :  删除左边连续子串直到碰到其他字符
            #print(word)
            l2=len(word)
            d=l-l2
            if d>9:
                d1=d//9
                d2=d%9
                comp+=('9'+c)*d1
                if d2:
                    comp+=str(d2)+c
            else:
                comp+=str(d)+c
            l=l2
        return comp

if __name__=='__main__':
    word='abcde'

    sol=Solution()
    ans=sol.compressedString(word)
    print(ans)

灵神的代码

其中enumerate是同时提取索引和元素(素数筛里面用的也是enumerate)

divmod( a,b )返回( a//b,a%b )

python 复制代码
class Solution:
    def compressedString(self, word: str) -> str:
        t = []
        i0 = -1
        for i, c in enumerate(word):
            if i + 1 == len(word) or c != word[i + 1]:
                k, rem = divmod(i - i0, 9)
                t.append(("9" + c) * k)
                if rem:
                    t.append(str(rem))
                    t.append(c)
                i0 = i
        return ''.join(t)

作者:灵茶山艾府
链接:https://leetcode.cn/problems/string-compression-iii/solutions/2790666/mo-ni-pythonjavacgo-by-endlesscheng-3hk7/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

46.全排列

注意itertools.permutations出来的是元组,得list

python 复制代码
from itertools import permutations

class Solution:
    def permute(self, nums):
        l=len(nums)
        ans=permutations(nums,l)
        lis=[]
        for i in ans:
            lis.append(list(i))
        return lis

if __name__=='__main__':
    nums=[1,2,3]

    sol=Solution()
    ans=sol.permute(nums)
    print(ans)

53.最大子数组和

我的第一想法是用前缀和之差,于是我直接暴力表示了

python 复制代码
class Solution:
    def maxSubArray(self, nums):
        pre=[[0,0]]
        l=len(nums)

        for i,k in enumerate(nums):
            #print(i,k)
            pre.append([pre[-1][0]+k,pre[-1][1]+1])
        
        #print(pre)

        ans=-float('inf')
        for su,n in pre:
            for j in range(n):
                now=su-pre[j][0]
                ans=max(ans,now)
        return ans
            

if __name__=='__main__':
    nums=[-2,1,-3,4,-1,2,1,-5,4]

    sol=Solution()
    ans=sol.maxSubArray(nums)
    print(ans)

因为 最大值= -最小值,所以我们其实可以在一边遍历数组计算前缀和的同时一边维护前缀和的最小值

请注意,由于题目要求子数组不能为空,应当先计算前缀和-最小前缀和,再更新最小前缀和。相当于不能在同一天买入股票又卖出股票。如果先更新最小前缀和,再计算前缀和-最小前缀和,就会把空数组的元素和 0 算入答案。(来自灵神)

python 复制代码
class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        ans = -inf
        min_pre_sum = pre_sum = 0
        for x in nums:
            pre_sum += x  # 当前的前缀和
            ans = max(ans, pre_sum - min_pre_sum)  # 减去前缀和的最小值
            min_pre_sum = min(min_pre_sum, pre_sum)  # 维护前缀和的最小值
        return ans
相关推荐
闪电麦坤9517 分钟前
数据结构:递归的种类(Types of Recursion)
数据结构·算法
互联网杂货铺42 分钟前
完美搭建appium自动化环境
自动化测试·软件测试·python·测试工具·职场和发展·appium·测试用例
Gyoku Mint1 小时前
机器学习×第二卷:概念下篇——她不再只是模仿,而是开始决定怎么靠近你
人工智能·python·算法·机器学习·pandas·ai编程·matplotlib
纪元A梦1 小时前
分布式拜占庭容错算法——PBFT算法深度解析
java·分布式·算法
莱茵菜苗1 小时前
Python打卡训练营day46——2025.06.06
开发语言·python
爱学习的小道长1 小时前
Python 构建法律DeepSeek RAG
开发语言·python
px不是xp1 小时前
山东大学算法设计与分析复习笔记
笔记·算法·贪心算法·动态规划·图搜索算法
luojiaao2 小时前
【Python工具开发】k3q_arxml 简单但是非常好用的arxml编辑器,可以称为arxml杀手包
开发语言·python·编辑器
英英_2 小时前
视频爬虫的Python库
开发语言·python·音视频