马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
目次
39.组合总和
回溯(单向剪枝)
3102.最小化曼哈顿距离
利用曼哈顿距离的性子
3163.压缩字符串3
46.全分列
53.最大子数组和
39.组合总和
39. 组合总和
注意:
set不能添加list得加元组
元组不可修改
sorted后得赋值
- 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开始
- 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 ✅ 找到结果
复制代码- 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. 最小化曼哈顿距离
本来我想用一半的二维矩阵来优化空间复杂度,但是这样反而得不偿失了,太绕了连正确答案都跑不出来,还是正常用二维的
这题的主要思路的思路就是枚举删的点,然后再枚举所有点的所有边(撤除当时删的点的),进行体现
- '''
- 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
利用曼哈顿距离的性子
- 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
- 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 )
- 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/
- 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
复制代码 46.全分列
注意itertools.permutations出来的是元组,得list
- 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.最大子数组和
我的第一想法是用前缀和之差,于是我直接暴力体现了
- 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 算入答案。(来自灵神)
- 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
复制代码
|