<?xml version="1.0" encoding="utf-8" ?><rss version="2.0"><channel><title><![CDATA[lemonmillie的博客]]></title><description><![CDATA[]]></description><link>https://blog.youkuaiyun.com/lemonmillie</link><language>zh-cn</language><generator>https://blog.youkuaiyun.com/</generator><copyright><![CDATA[Copyright &copy; lemonmillie]]></copyright><item><title><![CDATA[【LeetCode】2015. Average Height of Buildings in Each Segment 每段建筑物的平均高度]]></title><link>https://blog.youkuaiyun.com/lemonmillie/article/details/124925964</link><guid>https://blog.youkuaiyun.com/lemonmillie/article/details/124925964</guid><author>lemonmillie</author><pubDate>Mon, 23 May 2022 14:01:54 +0800</pubDate><description><![CDATA[扫描线（Sweep Line）算法。从左到右遍历每个出现过的坐标（不管是作为building起始还是结束）。
关键思想是：

永远维护一个[cur_s, x)的平均高度before（初始时假设为None）
处理坐标x处的所有出点和入点（顺序无关），得到处理之后的平均高度after
如果处理之后，平均高度发生了变化，那么就把[cur_s, x, before]加进去

实现扫描线可以用哈希数组或者堆。
heap
from heapq import heappush, heappop

class Sol...]]></description><category></category></item><item><title><![CDATA[【LeetCode】2250. Count Number of Rectangles Containing Each Point]]></title><link>https://blog.youkuaiyun.com/lemonmillie/article/details/124924164</link><guid>https://blog.youkuaiyun.com/lemonmillie/article/details/124924164</guid><author>lemonmillie</author><pubDate>Mon, 23 May 2022 11:38:17 +0800</pubDate><description><![CDATA[基本上就是Binary Search
简单二分
因为题目的height只有100种可能，我的naive的想法是统计每个height的width，然后遍历到每个点(x, y)的时候，把height&gt;=y的每个width数组都二分查找一遍……
from collections import defaultdict
from bisect import bisect_left

class Solution:
    def countRectangles(self, rectangles: List...]]></description><category></category></item><item><title><![CDATA[【LeetCode】1483. Kth Ancestor of a Tree Node 1483. 树节点的第 K 个祖先]]></title><link>https://blog.youkuaiyun.com/lemonmillie/article/details/124813059</link><guid>https://blog.youkuaiyun.com/lemonmillie/article/details/124813059</guid><author>lemonmillie</author><pubDate>Tue, 17 May 2022 08:09:18 +0800</pubDate><description><![CDATA[由于O(N^2)的存储会超内存限制，所以直接记忆化肯定凉了。
只能考虑O(NlogN)的存储，方法就对每个node都记下，它k=1,2,4,8,…时候的k祖先。比如，可以用f[h][node]表示node的2**h祖先是谁。
需要注意的是，记这个的时候也得做一些优化，直接暴力遍历还是会超时。原理就是：
node的2h2^h2h距离的祖先就是它2h−12^{h-1}2h−1祖先的2h−12^{h-1}2h−1祖先，f[h][node] = f[h-1][f[h-1][node]]。
然后在query的时候，.]]></description><category></category></item><item><title><![CDATA[【LeetCode】569. Median Employee Salary 员工薪水中位数]]></title><link>https://blog.youkuaiyun.com/lemonmillie/article/details/124812385</link><guid>https://blog.youkuaiyun.com/lemonmillie/article/details/124812385</guid><author>lemonmillie</author><pubDate>Tue, 17 May 2022 04:25:38 +0800</pubDate><description><![CDATA[第一次做到SQL的题。
window function
select
    id,
    company,
    salary
from (
    select
        *,
        (count(salary) over (partition by company)) / 2.0 as cnt,
        row_number() over (partition by company order by salary) as rk
    from Employee
) t..]]></description><category></category></item><item><title><![CDATA[【LeetCode】471. Encode String with Shortest Length 编码最短长度的字符串]]></title><link>https://blog.youkuaiyun.com/lemonmillie/article/details/124812226</link><guid>https://blog.youkuaiyun.com/lemonmillie/article/details/124812226</guid><author>lemonmillie</author><pubDate>Tue, 17 May 2022 02:41:57 +0800</pubDate><description><![CDATA[题解
这题其实分成了两个部分：

DP：把大问题分割成小问题
判断循环节：这样才能知道某段字符串可不可以缩

DP/问题切割
给定一段字符串s，如果存在某个中间位置k，把字符串分割成2部分s[:k]和s[k:]：

如果s[:k]由循环节组成，假设已知它可以缩成substr，那么问题就变成了F(s)=substr+F(s[k:])F(s) = \text{substr} + F(s[k:])F(s)=substr+F(s[k:])
类似地，如果s[k:]由循环节组成，同样假设它可以被缩成substr，那么.]]></description><category></category></item><item><title><![CDATA[【LeetCode】1655. Distribute Repeating Integers 分配重复整数]]></title><link>https://blog.youkuaiyun.com/lemonmillie/article/details/124797245</link><guid>https://blog.youkuaiyun.com/lemonmillie/article/details/124797245</guid><author>lemonmillie</author><pubDate>Mon, 16 May 2022 12:28:58 +0800</pubDate><description><![CDATA[一题多解。
首先理解问题，可以抽象为：

有若干物品，大小分别为quantity[i]。
假如某个数字重复x次，可理解为有一个容量为x的背包
要把物品放进背包里，问能不能放完

DFS
暴力解法，直接遍历所有可能，甚至也没有怎么剪枝，竟然也不超时……
class Solution:
    def canDistribute(self, nums: List[int], quantity: List[int]) -&gt; bool:
        packages = list(sorted(Coun.]]></description><category></category></item><item><title><![CDATA[【LeetCode】1580. Put Boxes Into the Warehouse II 把箱子放进仓库里 II]]></title><link>https://blog.youkuaiyun.com/lemonmillie/article/details/124778275</link><guid>https://blog.youkuaiyun.com/lemonmillie/article/details/124778275</guid><author>lemonmillie</author><pubDate>Sun, 15 May 2022 09:06:07 +0800</pubDate><description><![CDATA[简单贪心。
因为题目的规则，很容易可以想到不管从左边还是从右边塞入，warehouse的容量肯定是一直递减的。
所以很明显，最高的box如果从左边第一个，或者右边第一个开始就塞不进了，那么它就永远不可能塞进了。
而如果它可以塞进去，那么塞进左边第一个（或右边第一个）会是最优的吗？

是的。因为假设左边第一个位置不塞这个最高的，塞了次高的，那么由于后面的warehouse容量更小了，在最好的情况下也只能把最后的n-2个塞完，最高的这个永远塞不进去。所以：不塞这个最高的box不可能导致更差的结果。

那么...]]></description><category></category></item><item><title><![CDATA[【LeetCode】1654. Minimum Jumps to Reach Home 到家的最少跳跃次数]]></title><link>https://blog.youkuaiyun.com/lemonmillie/article/details/124701899</link><guid>https://blog.youkuaiyun.com/lemonmillie/article/details/124701899</guid><author>lemonmillie</author><pubDate>Wed, 11 May 2022 07:41:31 +0800</pubDate><description><![CDATA[BFS.
坑：

因为不能后跳2次，通过-b往回跳的点，依然可以试图利用+a走一次。因为通过+a走到的点既能前跳又能后跳，不用再遍历了；而通过-b走到的点只能前跳，所以可能的情况下还是要通过+a走一次探索一下后跳的可能性。由于坐标一定是非负的，这里我用负数来表示某坐标是通过后跳走到的，这样就和前跳分开记录visited了。
可以把visited和forbid用一个set记录
由于x轴无限长，有可能无限尝试都得不到-1，尤其是在a&lt;b的情况下。在a&gt;b的情况下容易证明最远走x+b就可以了。而a&.]]></description><category></category></item><item><title><![CDATA[【LeetCode】1353. Maximum Number of Events That Can Be Attended 最多可以参加的会议数目]]></title><link>https://blog.youkuaiyun.com/lemonmillie/article/details/124701730</link><guid>https://blog.youkuaiyun.com/lemonmillie/article/details/124701730</guid><author>lemonmillie</author><pubDate>Wed, 11 May 2022 03:30:38 +0800</pubDate><description><![CDATA[明显的贪心，把区间从小到大排序之后，发生的越早的、持续时间越短的会议越优先参加。
需要记录一下当前available的最早的天数（cur_s）。
比如：[1, 2], [1, 4], [2, 2], [3, 3], [5, 6]的情况
我们决定在第一天参加[1, 2]之后，cur_s就变成了2。
需要注意的是： 这时候在第2天才开始的会议就要加在一起讨论了！而那些在第1天开始的会议已经等价于在第2天才开始了（因为第1天已经被用了），也就是说，我们需要比较[2, 4]（原[1, 4]）和[2, 2]参加哪..]]></description><category></category></item><item><title><![CDATA[【LeetCode】1901. Find a Peak Element II 找出顶峰元素 II]]></title><link>https://blog.youkuaiyun.com/lemonmillie/article/details/124686510</link><guid>https://blog.youkuaiyun.com/lemonmillie/article/details/124686510</guid><author>lemonmillie</author><pubDate>Tue, 10 May 2022 13:47:00 +0800</pubDate><description><![CDATA[题目形容得很形象了，其实只要从任意一点出发，沿元素变大的方向走，走到再也走不了的时候，就遇到了峰值。
如果我们当前在某行的最大值处：
* 如果同一列的下面那行比它大，也就是说往下能继续找到峰顶
* 吃果同一列的上面那行比它大，也就是说往上继续能找到峰顶
* 都不是，那么当前点就是峰顶
因此我们可以对行进行二分：
class Solution:
    def findPeakGrid(self, mat: List[List[int]]) -&gt; List[int]:
        M = len..]]></description><category></category></item><item><title><![CDATA[【Leetcode】959. Regions Cut By Slashes 959. 由斜杠划分区域]]></title><link>https://blog.youkuaiyun.com/lemonmillie/article/details/100167891</link><guid>https://blog.youkuaiyun.com/lemonmillie/article/details/100167891</guid><author>lemonmillie</author><pubDate>Fri, 30 Aug 2019 23:43:16 +0800</pubDate><description><![CDATA[解法
就是并查集，把每个1x1的方格再划分成4个格子，比如这样：

class Solution:
    def regionsBySlashes(self, grid: List[str]) -&gt; int:
        n = len(grid)
        # print(n)
        num = n*n
        f = list(range(4*num...]]></description><category></category></item><item><title><![CDATA[【Leetcode】795. Number of Subarrays with Bounded Maximum 795. 区间子数组个数]]></title><link>https://blog.youkuaiyun.com/lemonmillie/article/details/100097950</link><guid>https://blog.youkuaiyun.com/lemonmillie/article/details/100097950</guid><author>lemonmillie</author><pubDate>Tue, 27 Aug 2019 13:43:35 +0800</pubDate><description><![CDATA[解法
就是 最大值不超过R的子数组里，也包括了最大值&lt;L的子数组，以及最大值在[L,R]里的子数组，而这两部分是不相交的，所以利用互斥性，直接计算出【最大值不超过R的子数组】以及【最大值&lt;L的子数组】的个数，然后相减即可
class Solution:
    def numSubarrayBoundedMax(self, A: List[int], L: int, R: int) ...]]></description><category></category></item><item><title><![CDATA[【Kickstart】2019 Round C - Catch Some]]></title><link>https://blog.youkuaiyun.com/lemonmillie/article/details/100067103</link><guid>https://blog.youkuaiyun.com/lemonmillie/article/details/100067103</guid><author>lemonmillie</author><pubDate>Sun, 25 Aug 2019 20:21:52 +0800</pubDate><description><![CDATA[解法
假如最后必须返回终点，可以DP
每个颜色记录狗的位置，从小到大排序
对于f[i][s]表示，只考虑前i个颜色时，访问s个狗需要的最小时间
那么有:
f[i][s] = min(f[i-1][s], f[i-1][s-j-1]+2*P[i][j] for j in range(P[i])
但是现在需要考虑最后不回家，那么需要增加一维，f[i][s][0]表示只考虑前i个颜色并且没有选择最后颜色...]]></description><category></category></item><item><title><![CDATA[【Kickstart】2019 Round C - Circuit Board]]></title><link>https://blog.youkuaiyun.com/lemonmillie/article/details/100066856</link><guid>https://blog.youkuaiyun.com/lemonmillie/article/details/100066856</guid><author>lemonmillie</author><pubDate>Sun, 25 Aug 2019 19:59:14 +0800</pubDate><description><![CDATA[解法
算出每列往左的长度，然后就能转化成求直方图最大矩形的问题
至于如何求第i行第j列往左有多长，需要每行维护两个双向队列minStack、maxStack和一个左边界l，对于范围(l,j]，minStack队头是这个范围内最小值（以及它在的位置），从队头到队尾，值和索引都是递增的
类似地，maxStack队头是这个范围内最大值（以及它在的位置），从队头到队尾，值递减，索引都是递增的
现在如果ma...]]></description><category></category></item><item><title><![CDATA[【Kickstart】2019 Round C - Wiggle Walk]]></title><link>https://blog.youkuaiyun.com/lemonmillie/article/details/100066853</link><guid>https://blog.youkuaiyun.com/lemonmillie/article/details/100066853</guid><author>lemonmillie</author><pubDate>Sun, 25 Aug 2019 19:58:39 +0800</pubDate><description><![CDATA[解法
rc个点映射到一维ID，然后维护4个方向的并查集：
比如E方向的并查集，最开始，每个点都代表它自己，当某个点被访问过之后，如果有人向东走到了这个点，那么它应该直接走到这个点东边第一个没有被访问的点，那就是这个点的root
所以算法应该是这样的，对于每个被访问到的点x，找到它周围四个点e``w``s``n，然后E.join(x,e)，……
join的时候要注意顺序，使得根永远是一个没被访问过的...]]></description><category></category></item><item><title><![CDATA[【Kickstart】2019 Round E - Street Checkers]]></title><link>https://blog.youkuaiyun.com/lemonmillie/article/details/100066807</link><guid>https://blog.youkuaiyun.com/lemonmillie/article/details/100066807</guid><author>lemonmillie</author><pubDate>Sun, 25 Aug 2019 19:54:26 +0800</pubDate><description><![CDATA[解法
就是要求[L,R]里的每个整数中，有多少个整数的奇因子和偶因子个数之差不超过2.

对于奇数来说，它只可能有奇因子，那么需要奇因子个数少于2，那么只能是质数或1
对于偶数来说，假设x=2m⋅nx = 2^m\cdot nx=2m⋅n，其中n是奇数，那么x的因子有这几种情况：

奇x偶： 那么应该是(a,b⋅2m)(a,b\cdot 2^m)(a,b⋅2m)，其中ab=n，这时候不管a和b相不...]]></description><category></category></item><item><title><![CDATA[【Kickstart】2019 Round E - Code-Eat Switcher]]></title><link>https://blog.youkuaiyun.com/lemonmillie/article/details/100066647</link><guid>https://blog.youkuaiyun.com/lemonmillie/article/details/100066647</guid><author>lemonmillie</author><pubDate>Sun, 25 Aug 2019 19:37:46 +0800</pubDate><description><![CDATA[解法
对于每天的a和b，我们不妨假设所有的时间都用来coding，这样能得到totalC的coding时间

显然，如果totalC&lt;a，这天显然不能完成
否则，我们假设able = totalC-a，这表示多出来了able的coding时间，这些时间可以转化成吃饭时间
我们肯定更prefer效率高的转化，比如我同样减少1单位的coding时间，在不同的timeslot可能会增加不同的吃饭时...]]></description><category></category></item><item><title><![CDATA[【Kickstart】2019 Round E - Cherries Mesh]]></title><link>https://blog.youkuaiyun.com/lemonmillie/article/details/100066543</link><guid>https://blog.youkuaiyun.com/lemonmillie/article/details/100066543</guid><author>lemonmillie</author><pubDate>Sun, 25 Aug 2019 19:26:23 +0800</pubDate><description><![CDATA[解法
就是想求最小生成树，但是边的权重只有1和2，而且给出了权重为1的边，剩余边权重都为2
显然，可以用最小生成树的某个算法，权重为1的边只加上那些能联通两个不同集合的边
输入完毕之后会得到k个联通分量，需要k-1条权重为2的边，所以ans要再加上2(k-1)
#include &lt;stdio.h&gt;
#include &lt;string&gt;
#include &lt;iostrea...]]></description><category></category></item><item><title><![CDATA[【Leetcode】1144. Decrease Elements To Make Array Zigzag 1144. 递减元素使数组呈锯齿状]]></title><link>https://blog.youkuaiyun.com/lemonmillie/article/details/100045334</link><guid>https://blog.youkuaiyun.com/lemonmillie/article/details/100045334</guid><author>lemonmillie</author><pubDate>Fri, 23 Aug 2019 20:05:03 +0800</pubDate><description><![CDATA[解法
可以从左向右扫一遍，直接取最少次数就好
但是还有一种巧妙的解法
如果对于数字a,b,c，想使得a&gt;b&lt;c， 那么只需要令b = max(b, min(a,c)-1)，就能获得最少的操作次数
那么对于其中一种pattern，就是使偶数位置满足a&gt;b&lt;c， 另一种pattern， 就是使奇数位置满足a&gt;b&lt;c
class Solution:
    def...]]></description><category></category></item><item><title><![CDATA[【Leetcode】1153. String Transforms Into Another String 1153. 字符串转化]]></title><link>https://blog.youkuaiyun.com/lemonmillie/article/details/100045180</link><guid>https://blog.youkuaiyun.com/lemonmillie/article/details/100045180</guid><author>lemonmillie</author><pubDate>Fri, 23 Aug 2019 19:52:26 +0800</pubDate><description><![CDATA[解法
遍历一遍str1，就知道str1的每个字符应该映射到谁了
但是1个字符不能映射到2个字符 同时 str1里的字符个数应该少于str2里的字符个数
此外，如果str2有26个字符时，除非两个字符串相等，否则不可能转化成功，因为str1此时也得有26个字符，但是不管动了哪个字符，映射完之后就只有25个字符了，这时候无法再映射回26个字符
class Solution:
    def can...]]></description><category></category></item></channel></rss>