| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 数据结构与算法 -> LeetCode 力扣双周赛 60 -> 正文阅读 |
|
[数据结构与算法]LeetCode 力扣双周赛 60 |
周赛传送门还是两道题,怎么办呢? 1991. 找到数组的中间位置思路:枚举,求和 时间复杂度: O ( n ) O(n) O(n) 首先求出 n n n 个数字的累加和 s u m sum sum。 然后枚举位置 i i i,并在枚举过程中计算前缀和 p a r t part part,如果 p a r t = s u m ? p a r t ? n u m s i part = sum - part - nums_i part=sum?part?numsi?,则 i i i 即为答案。如果不存在这样的 i i i,则答案为 ? 1 -1 ?1。 完整代码如下:
1992. 找到所有的农场组思路:暴力枚举,标记 时间复杂度: O ( n ? m ) O(n*m) O(n?m) 从上到下,从左到右依次枚举枚举 ( i , j ) (i,j) (i,j),如果 l a n d i , j land_{i,j} landi,j? 为 1,则说明 ( i , j ) (i,j) (i,j) 为一块农场组的左上角。 接着,从 ( i , j ) (i,j) (i,j) 找出该农场组的高和宽,并将属于该农场组的 l a n d x , y land_{x,y} landx,y? 全部置为 0。 不难发现,每个初始值为 1 的 l a n d ( i , j ) land_(i,j) land(?i,j) 最多会被访问三次,每个初始值为 0 0 0 的 l a n d ( i , j ) land_(i,j) land(?i,j) 会被访问一次。因此总的时间复杂度为 O ( n ? m ) O(n*m) O(n?m)。
1993. 树上的操作思路:模拟,树的遍历 时间复杂度: O ( n ? o p ) O(n*op) O(n?op),其中 n n n 是节点的数量, o p op op 是操作次数(确切的说,是 upgrade 的次数)。 设有一维数组 l o c k e r locker locker, l o c k e r i locker_i lockeri? 表示第 i i i 个节点的持有者。如果 l o c k e r i locker_i lockeri? 为 -1,代表对应节点未上锁。 lock 操作判断 l o c k e r i locker_i lockeri? 是否为 ? 1 -1 ?1 即可:
时间复杂度为 O ( 1 ) O(1) O(1)。 unlock 操作判断 l o c k e r i locker_i lockeri? 是否与 u s e r user user 相等 :
时间复杂度为 O ( 1 ) O(1) O(1)。 upgrade 操作首先,检查
n
u
m
num
num 到
r
o
o
t
root
root 这条路径上的节点是否全未上锁。 如果上述条件都满足,则更新 l o c k e r n u m locker_num lockern?um 并将子树中的节点全部解锁。 时间复杂度为 O ( n ) O(n) O(n)。
1994. 好子集的数目思路:状态压缩,滚动数组,组合 时间复杂度: O ( s + m ? 2 p ) O(s+m*2^p) O(s+m?2p)。 时间复杂度的标识比较啰嗦,这里解释下:
假设用前 i ? 1 i-1 i?1 个数字可构造出 k k k 个好子集,记为 S 1 S_1 S1?, S 2 S_2 S2?,…, S k S_k Sk?。现在要用这 k k k 个集合以及数字 n u m s i nums_i numsi? 构造出一批新的集合,该如何构造呢? 不难想到,如果 n u m s i nums_i numsi? 本身包含重复的质因子,如 12 12 12 可拆分为 2 , 2 , 3 2,2,3 2,2,3,则显然无法构造出新的好子集。因此,只需考虑本身无重复质因子的 n u m s i nums_i numsi?。 新的好子集可由两种方式构造而来:
不难想到,可遍历所有的 S j S_j Sj?,判断 S j S_j Sj? 包含的质因子是否与 n u m s i nums_i numsi? 的有重复,如果没有重复,则得到了一个新的好子集 S j ′ = { S j , n u m s i } S_j' = \{S_j, nums_i\} Sj′?={Sj?,numsi?}。 但是,
k
k
k 很大,枚举的效率太低,不能接受。继续分析,由于
n
u
m
s
i
nums_i
numsi? 的取值范围为 [1,30],因此
S
j
S_j
Sj? 包含的质因子不外乎以下十个素数: 考虑把包含相同质因子的好子集划分为一类,则最多有 2 10 ? 1 = 1023 2^{10}-1=1023 210?1=1023 种好子集。 设有二维数组 d p dp dp。 d p i , m a s k dp_{i,mask} dpi,mask? 表示前 i i i 个数字中,恰好包含素数集 m a s k mask mask 的好子集的数量。 m a s k mask mask 最低位的十个比特对应上述十个素数,比特值为 1 代表包含了对应素数,反之则未包含。 m a s k mask mask 的取值范围为 [ 0 , 1023 ] [0,1023] [0,1023], m a s k = 0 mask=0 mask=0 表示空集或仅含 1 1 1 的集合的数量。 设 n u m s i nums_i numsi? 包含的素数集为 q i q_i qi?。特别的,如果 n u m s i nums_i numsi? 包含重复的素数,则将 q i q_i qi? 置为 ? 1 -1 ?1。 于是可得出状态转移方程:
上述方程的时间复杂度太高了,大约是 1 e 5 ? 2 1 0 = 1 e 9 1e5*2^10=1e9 1e5?210=1e9 量级的,基本是超时啦。 继续分析,考虑到里面有大量重复的数字,我们先统计每个数字出现的次数,记为 c n t cnt cnt。 c n t i cnt_i cnti? 代表数字 i i i 在 n u m s nums nums 中出现的次数,显然在本题中 i ∈ [ 1 , 30 ] i\in [1,30] i∈[1,30]。 因此, d p i , m a s k dp_{i,mask} dpi,mask? 的含义变化为在前 i i i 种数字中,恰好包含素数集 m a s k mask mask 的好子集的数量。设 q i q_i qi? 为数字 i i i 包含的素数集。 状态转移方程如下:
最终答案为
|
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/26 2:04:35- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |