LeetCode-27
[Medium] 29. 两数相除
分析
- 只能用加减法,最朴素的方法是循环相减/加,直到小于0/大于0,计算加/减的次数
- 这样算法是o(n),考虑到
i+=i
或者i<<=1
相当于i*=2
,i>>=1
相当于i/=2
- 只考虑divisor, divident都大于0的情况,先找到整数p,使得 ,若divident为0,则商为ratio,否则重复上面的过程,直到divident为0。
- 考虑divisor, divident到可能正,可能负,而负数的范围大于正数,直接将所有整数变成负数,并记录符号
- 注意取相反数的时候要用位运算
~x+1
代码
1 | class Solution { |
275. H 指数 II
代码
1 | class Solution { |
优化
1 | class Solution { |
274. H 指数
代码
1 | class Solution { |
2558. 从数量最多的堆取走礼物
1 | class Solution { |
1465. 切割后面积最大的蛋糕
1 | class Solution { |
2520. 统计能整除数字的位数
1 | class Solution { |
2698. 求一个整数的惩罚数
思路
- 首先要计算出所有满足sum(split(i*i)) == i的元素
- 发现很少,直接放到数组里去查表
- 对于一个数i,希望它拆分后和等于target
- 先分成a,b两份,判断是否等于,等于return true,不等于就把a分开(递归)
代码
1 | class Solution { |
1155. 掷骰子等于目标和的方法数
思路
- 先暴力递归,然后发现可以总结出dp公式,然后把递归改成dp尝试,成功了
代码
1 | class Solution { |
优化
观察代码可知,dp[i][t]就是dp[i-1][t-1]+…dp[i-1][t-k],可以用前缀和优化
1 | class Solution { |
1402. 做菜顺序
- 一眼dp,鉴定为,纯纯的简单题
- 一遍就做对啦哈哈哈
1 | class Solution { |
优化
dp数组和sum数组可以优化掉
1 | class Solution { |
2678. 老人的数目
1 | class Solution { |
2316. 统计无向图中无法互相到达点对数
1 | class Solution { |
并查集
- 这里一直写不出来,发现并查集无法把所有相连的点归到一个集合中,因为在遍历的时候没有用union操作
1 | class Solution { |
继续优化
- 换个公式减少一次循环
1 | class Solution { |
2525. 根据规则将箱子分类
1 | class Solution { |
117. 填充每个节点的下一个右侧节点指针 II
思路
- 首先想到的就是层次遍历,非常简单
- 对于进阶使用
O(1)
空间的算法,一直没想到利用已有的next指针- 树每层最左侧节点找parent,把同层都连起来就好
1 | class Solution { |
整理下代码
1 | class Solution { |
2127. 参加会议的最多员工数
并查集
- 一个重要结论,图中一定有环(n个节点,大于n-1条边)
- 如果环的大小大于2,则只能将环上的节点上桌,支链上的点无法上桌
- 如果环的大小不大于2,则环上节点的最长支链也可以跟着上桌
- 多个环长为2的子图(不论是否有支链),都可以全部上桌
故,统计所有环长大于2的最大环长,为maxRing
统计所有环长不大于2的环长之和,以及环上各节点的最大之链长度之和,为maxNumber
返回max(maxRing, maxNumber)
步骤
- 并查集将节点分类
- degree统计每个节点的入度
- dSetSize统计每个集合的大小
- 按照是否存在入度为0的点,将子图划分两类
- 存在,则图含有支链,计算环的长度(findMaxRing)
- 大于2,统计最大环长(maxRing)
- 不大于2,从任意度为0的节点开始遍历,将环上节点的visited变成非0,并标记该子图为
is2
,累加maxNumber(环长为2,都可以上桌)
- 不存在,则图不含有支链,计算环的长度(findMaxRing)
- 大于2,统计最大环长(maxRing)
- 不大于2,累加如maxNumber(环长为2,都可以上桌)
- 存在,则图含有支链,计算环的长度(findMaxRing)
- 对所有入度为0,且所在子图是
is2
的节点,计算该点到环上点的距离为支链长度,记录最大支链长度 - 所有最大支链长度累加maxNumber
- 返回max(maxNumber, maxRing)
时间 1848 ms 击败 5.2%
内存 98.4 MB 击败 35.8%
1 | class Solution { |
- 优化
上面的代码在遇到有公共部分的支链,(会分叉的支链时),会导致重叠部分反复被访问
使用arcFav统计被喜欢图,根据被喜欢图从环上开始寻找最大支链,可以避免,速度也得到了极大的优化
时间 284ms 击败 12.78% 使用 C++ 的用户
内存 166.84MB 击败 25.57% 使用 C++ 的用户
1 | class Solution { |
并查集+拓扑排序
1 | class Solution { |
更慢了,原因是不能在拓扑排序的同时计算最大支链长度
优化掉并查集
- 在拓扑排序中寻找最长支链,为每个节点定义f(x)
- $ f(x) = max_{i=0}^j(f(aFav(x)_i) + 1) $
- 每个节点初始为0,拓扑排序时,每次i将j的degree被减小,其值为max(f(i)+1, f(j))
1 | class Solution { |