当前位置: 首页 > news >正文

LeetCode Hot 100 Python (61~70)

分割回文串:中等

给你一个字符串 s,请你将 s 分割成一些 子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。

示例

1

2

输入

s = "aab"

s = "a"

输出

[["a","a","b"],["aa","b"]]

[["a"]]

法一:输入的视角(逗号选或不选)

假设每对相邻字符之间有个逗号,那么就看每个逗号是选还是不选。

也可以理解成:是否要把 s[i] 当成分割出的子串的最后一个字符。注意 s[n−1] 一定是最后一个字符,一定要选。

class Solution:def partition(self, s: str) -> List[List[str]]:n = len(s)ans = []path = []# 考虑 i 后面的逗号怎么选# start 表示当前这段回文子串的开始位置def dfs(i: int, start: int) -> None:if i == n:  # s 分割完毕ans.append(path.copy())  # 复制 pathreturn# 不选 i 和 i+1 之间的逗号(i=n-1 时一定要选)if i < n - 1:# 考虑 i+1 后面的逗号怎么选dfs(i + 1, start)# 选 i 和 i+1 之间的逗号(把 s[i] 作为子串的最后一个字符)t = s[start: i + 1]if t == t[::-1]:  # 判断是否回文path.append(t)# 考虑 i+1 后面的逗号怎么选# start=i+1 表示下一个子串从 i+1 开始dfs(i + 1, i + 1)path.pop()  # 恢复现场dfs(0, 0) 

法二:答案的视角(枚举子串结束位置)

class Solution:def partition(self, s: str) -> List[List[str]]:n = len(s)ans = []path = []# 考虑 s[i:] 怎么分割def dfs(i: int) -> None:if i == n:  # s 分割完毕ans.append(path.copy())  # 复制 pathreturnfor j in range(i, n):  # 枚举子串的结束位置t = s[i: j + 1]  # 分割出子串 tif t == t[::-1]:  # 判断 t 是不是回文串path.append(t)# 考虑剩余的 s[j+1:] 怎么分割dfs(j + 1)path.pop()  # 恢复现场dfs(0)return ans

N皇后:困难

按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。

皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。

给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。

每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。

示例

1

2

输入

n = 4

n = 1

输出

[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]

[["Q"]]

解释

如上图所示,4 皇后问题存在两个不同的解法。

排列型回溯:

本题和 46. 全排列 的关系是什么?由于每行恰好放一个皇后,记录每行的皇后放在哪一列,可以得到一个 [0,n−1] 的排列 queens。示例 1 的两个图,分别对应排列 [1,3,0,2] 和 [2,0,3,1]。所以我们本质上是在枚举列号的全排列。

如何 O(1) 判断两个皇后互相攻击?由于我们保证了每行每列恰好放一个皇后,所以只需检查斜方向。对于 ↗ 方向的格子,行号加列号是不变的。对于 ↖ 方向的格子,行号减列号是不变的。如果两个皇后,行号加列号相同,或者行号减列号相同,那么这两个皇后互相攻击。

如何 O(1) 判断当前位置被之前放置的某个皇后攻击到?额外用两个数组 diag1 diag2分别标记之前放置的皇后的行号加列号,以及行号减列号。如果当前位置的行号加列号在diag1中(标记为 true),或者当前位置的行号减列号在diag2中(标记为 true),那么当前位置被之前放置的皇后攻击到,不能放皇后。

class Solution:def solveNQueens(self, n: int) -> List[List[str]]:ans = []queens = [0] * n  # 皇后放在 (r,queens[r])col = [False] * ndiag1 = [False] * (n * 2 - 1)diag2 = [False] * (n * 2 - 1)def dfs(r: int) -> None:if r == n:ans.append(['.' * c + 'Q' + '.' * (n - 1 - c) for c in queens])return# 在 (r,c) 放皇后for c, ok in enumerate(col):if not ok and not diag1[r + c] and not diag2[r - c]:  # 判断能否放皇后queens[r] = c  # 直接覆盖,无需恢复现场col[c] = diag1[r + c] = diag2[r - c] = True  # 皇后占用了 c 列和两条斜线dfs(r + 1)col[c] = diag1[r + c] = diag2[r - c] = False  # 恢复现场dfs(0)return ans

A000170 - OEIS

搜索插入位置:简单

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

1

2

3

输入

nums = [1,3,5,6], target = 5

nums = [1,3,5,6], target = 2

nums = [1,3,5,6], target = 7

输出

2

1

4

题意概括

返回 nums 中的第一个(最左边的)大于或等于 target 的数的下标。如果所有数都小于 target,返回 nums 的长度。

下面的代码包含闭区间左闭右开区间开区间三种写法。

# lower_bound 返回最小的满足 nums[i] >= target 的 i
# 如果数组为空,或者所有数都 < target,则返回 len(nums)
# 要求 nums 是非递减的,即 nums[i] <= nums[i + 1]# 闭区间写法
def lower_bound(nums: List[int], target: int) -> int:left, right = 0, len(nums) - 1  # 闭区间 [left, right]while left <= right:  # 区间不为空# 循环不变量:# nums[left-1] < target# nums[right+1] >= targetmid = (left + right) // 2if nums[mid] < target:left = mid + 1  # 范围缩小到 [mid+1, right]else:right = mid - 1  # 范围缩小到 [left, mid-1]return left# 左闭右开区间写法
def lower_bound2(nums: List[int], target: int) -> int:left = 0right = len(nums)  # 左闭右开区间 [left, right)while left < right:  # 区间不为空# 循环不变量:# nums[left-1] < target# nums[right] >= targetmid = (left + right) // 2if nums[mid] < target:left = mid + 1  # 范围缩小到 [mid+1, right)else:right = mid  # 范围缩小到 [left, mid)return left  # 或者 right# 开区间写法
def lower_bound3(nums: List[int], target: int) -> int:left, right = -1, len(nums)  # 开区间 (left, right)while left + 1 < right:  # 区间不为空mid = (left + right) // 2# 循环不变量:# nums[left] < target# nums[right] >= targetif nums[mid] < target:left = mid  # 范围缩小到 (mid, right)else:right = mid  # 范围缩小到 (left, mid)return rightclass Solution:def searchInsert(self, nums: List[int], target: int) -> int:return lower_bound(nums, target)  # 选择其中一种写法即可

时间复杂度

空间复杂度

O(log n)

O(1)

其中 n 为 nums 的长度

仅用到若干额外变量

为什么不在二分的过程中,找到 target 就立刻返回?这种写法适用范围很窄。在有多个等于 target 的数的情况下,如果在二分的过程中立刻返回,我们得到的可能不是第一个等于 target 的数的下标。为什么返回第一个等于 target 的数的下标更好呢?因为这可以解决更复杂的题目,比如给你一个有序数组 [1,1,3,3,3,3,5],让你计算有多少个数小于 3。我们可以二分查找第一个等于 3 的数的下标 2,那么下标小于 2 的数就是元素值小于 3 的数,这有 2 个。对比可以发现,如果在二分中途就立刻返回,我们不一定找到的是第一个等于 3 的数的下标,所以不一定能算出正确答案 2。

为什么代码没有特判所有数都小于 target 的情况?如果所有数都小于 target,那么循环中更新的只有 left,无论下面哪种二分写法,最后都一定会返回数组长度,所以无需特判这种情况。

如果所有数都大于 target 呢?代码会返回 0。

是否需要特判 nums[mid]=target 的情况?可以,但没必要。

搜索二维矩阵:中等

给你一个满足下述两条属性的 m x n 整数矩阵:

  • 每行中的整数从左到右按非严格递增顺序排列。
  • 每行的第一个整数大于前一行的最后一个整数。

给你一个整数 target ,如果 target 在矩阵中,返回 tr

http://www.dtcms.com/a/362271.html

相关文章:

  • 芯片的可编程字
  • Ps画笔和橡皮擦工具
  • 分布式事务相关02
  • 国内服务器如何安装docker或者是1panel
  • 关闭页面强制清除所有循环定时器
  • Linux 进程间通信(IPC)
  • Android14 init.rc各个阶段的主要操作
  • authentication port-control auto 和 dot1x port-control auto
  • Shell 编程:正则表达式与文本处理器
  • 软考-操作系统-错题收集(1)进程P的页面变换
  • 分布式一致性算法相关
  • 【Audio】切换至静音或振动模式时媒体音自动置 0
  • 基于SpringBoot+MYSQL开发的师生成果管理系统
  • 解锁Git仓库瘦身秘籍,git-sizer真香警告
  • Next.js渲染模式:SSR、SSG与ISR揭秘
  • Python实现点云渲染可视化杂记(直接、彩虹渐变、柱状、饼状和T-SNE赋色)
  • The Algorithmic Foundations of Differential Privacy - 2
  • 8Lane V-by-One HS LVDS FMC Card
  • 【开题答辩全过程】以 智慧药店管理系统的实现与设计为例,包含答辩的问题和答案
  • 基于单片机智能空调/温度控制系统
  • GaussDB 集群故障cm_ctl: can‘t connect to cm_server
  • API安全厂商F5首发后量子加密方案,为企业后量子时代加固防线
  • Java中方法的参数传递
  • TFT屏幕:STM32硬件SPI+DMA+队列自动传输
  • 【无标题】训练、推理适用的数据类型
  • C++ 学习与 CLion 使用:(五)数据类型,包括整型、实型、字符型、转义字符、字符串、布尔型
  • 椭圆曲线的数学基础
  • 【算法专题训练】17、双向链表
  • openEuler2403部署Redis8集群
  • AI推理方法演进:Chain-of-Thought、Tree-of-Thought与Graph-of-Thought技术对比分析