-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
137 lines (67 loc) · 48.6 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>yulinliang</title>
<link href="http://yulinliang.com/atom.xml" rel="self"/>
<link href="http://yulinliang.com/"/>
<updated>2020-12-28T06:09:04.047Z</updated>
<id>http://yulinliang.com/</id>
<author>
<name>John Doe</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>Hexo主题开发</title>
<link href="http://yulinliang.com/2020/12/27/Hexo%E4%B8%BB%E9%A2%98%E5%BC%80%E5%8F%91/"/>
<id>http://yulinliang.com/2020/12/27/Hexo%E4%B8%BB%E9%A2%98%E5%BC%80%E5%8F%91/</id>
<published>2020-12-28T06:06:02.000Z</published>
<updated>2020-12-28T06:09:04.047Z</updated>
<content type="html"><![CDATA[<hr><p>Hexo是一个很轻便简洁的博客框架,没有太多的学习难度,如果对于博客功能和样式没有太多要求,几乎只需要安装,学会如何创建和发布博客即可。<br>对于一个程序员来说,当对于下载的主题有定制化需求的时候,总感觉不如直接撸一个属于自己的主题,抱着这种想法,时隔很久之后又重新开始了web的开发。</p><h1 id="主题开发"><a href="#主题开发" class="headerlink" title="主题开发"></a>主题开发</h1><h3 id="hexo-目录结构"><a href="#hexo-目录结构" class="headerlink" title="hexo 目录结构"></a>hexo 目录结构</h3><p>在本地的blog目录下运行<code>hexo init</code>之后,hexo会进行初始化,为我们自动生成一些文件和目录。以下为hexo的默认目录结构。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">.</span><br><span class="line">|-- _config.yml // 博客的总配置文件</span><br><span class="line">|-- package-lock.json // 支持hexo运行的nodejs包</span><br><span class="line">|-- package.json // 自定义的nodejs包</span><br><span class="line">|-- node_modules/ // nodejs的依赖包,也可以自定义添加插件</span><br><span class="line">|-- scaffolds/ // 模板文件夹,包含page,post draft三种模板,对应页面,发布的文章和草稿</span><br><span class="line">|-- source/ // 资源文件夹。用来存放博客的图片,文章以及各种页面文件</span><br><span class="line">|-- themes/ // 主题文件夹,每个主题都有一个单独的文件夹,默认主题为landscape</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>由于我们在开发过程中需要不断地查看运行效果,所以比较方便的就是直接创建一个新的Blog文件夹,然后让clone自己的主题repo到<code>themes/</code>目录下,接着对根目录下的<code>_config.yml</code>进行修改,把主题替换成<code>themes/</code>下的目录名,从而启用新的主题。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"># Extensions</span><br><span class="line">## Plugins: https://hexo.io/plugins/</span><br><span class="line">## Themes: https://hexo.io/themes/</span><br><span class="line">theme: future</span><br></pre></td></tr></table></figure><p>在博客目录下(注意不是主题目录)运行<code>hexo s</code>启动hexo server,通过访问 <a href="http://localhost:4000/">http://localhost:4000</a> 可以查看到一个空白的界面,那是因为我们的新主题目录下没有任何内容。</p><h3 id="Hexo-主题目录"><a href="#Hexo-主题目录" class="headerlink" title="Hexo 主题目录"></a>Hexo 主题目录</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">/themes/future</span><br><span class="line"></span><br><span class="line">|-- _config.yml // 主题的配置文件</span><br><span class="line">|-- languages/ // 国际化文件夹,支持多语言</span><br><span class="line">|-- layout/ // 页面配置文件,存放我们的ejs文件</span><br><span class="line"> |-- layout.ejs // 布局文件的总入口,所有页面都是按照其来进行渲染</span><br><span class="line"> |-- index.ejs // 主页的布局文件</span><br><span class="line"> |-- post.ejs // 博客文章详情页的布局文件</span><br><span class="line">|-- source/ // 主题配置文件,存放css,font,js等文件</span><br></pre></td></tr></table></figure><ul><li><code>_config.yml</code>不同于根目录下的<code>_config.yml</code>,这是你自己主题的配置文件,是我们提供给用户进行个人博客差异化的配置入口,通过设置不同的配置项来修改主题的布局样式等。下面就是一个主题<code>_config.yml</code>的例子,通过<code>theme.变量名</code>来获取配置信息,如我们可以通过<code>theme.author</code>获取到用户提供的作者信息<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">author: Yulin Liang(梁煜麟)</span><br><span class="line">description: Make coding more interesting</span><br><span class="line">avatar: https://i.loli.net/2020/12/09/liWow1fZmFVJEYO.jpg</span><br><span class="line">url: https://yulinliang.com</span><br><span class="line">subtitle: try to make life better</span><br></pre></td></tr></table></figure></li><li><code>source/</code>是用来存放资源文件的,我们的stylus,js和font文件都是存放在该目录下的。</li><li><code>layout/</code>就是我们ejs的文件夹,所有的布局文件都是存放在其中的。</li></ul><h3 id="主题开发-1"><a href="#主题开发-1" class="headerlink" title="主题开发"></a>主题开发</h3><p>Hexo支持主流的模板引擎,如:<code>Ejs</code>,<code>Jade</code>,<code>Swing</code>等,同时也支持大量的CSS预处理,如<code>sass</code>, <code>Stylus</code>,<code>Less</code>等。在这里我选择的和默认主题<code>landscape</code>样,<code>ejs</code> + <code>stylus</code>.</p><ul><li><p>首先我们需要创建<code>layout.ejs</code>, <code>index.ejs</code>,<code>post.ejs</code>三个文件。</p></li><li><p>前面我们提到<code>layout.ejs</code>是整个博客布局的总入口,这以为着如果我们在<code>layout.ejs</code>中添加了header和footer之后,所有的页面都会存在着header和footer。</p></li><li><p>所以我们可以在<code>layout.ejs</code>中添加如下代码:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><!DOCTYPE <span class="meta-keyword">html</span>></span></span><br><span class="line"><span class="tag"><<span class="name">html</span>></span></span><br><span class="line"><span class="tag"><<span class="name">head</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">title</span>></span><span class="tag"></<span class="name">title</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"utf-8"</span>></span></span><br><span class="line"><span class="tag"></<span class="name">head</span>></span></span><br><span class="line"><span class="tag"><<span class="name">body</span>></span></span><br><span class="line"></span><br><span class="line"> Hello World</span><br><span class="line"></span><br><span class="line"><span class="tag"></<span class="name">body</span>></span></span><br><span class="line"><span class="tag"></<span class="name">html</span>></span></span><br></pre></td></tr></table></figure><p>启动hexo server之后刷新localhost:4000,我们可以看到hello world已经打印出来了。</p></li></ul><p><img src="https://i.loli.net/2020/12/28/esj4c6kLZlz1Ot3.png" alt="demo"></p><ul><li><p>接下来我们如何才能让<code>post.ejs</code>和<code>index.ejs</code>得到显示呢?Hexo为我们提供了大量的api接口,其中<code><%- body %></code>会引入post.ejs和index.ejs,在首页会自动选择index.ejs进行渲染,而博客正文页面则使用post.ejs。接下来我们修改一下index.ejs和post。</p><p>index.ejs</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">div</span>></span></span><br><span class="line">这里是index.ejs</span><br><span class="line"><span class="tag"></<span class="name">div</span>></span></span><br></pre></td></tr></table></figure><p>post.ejs</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">div</span>></span></span><br><span class="line">这里是post.ejs</span><br><span class="line"><span class="tag"></<span class="name">div</span>></span></span><br></pre></td></tr></table></figure><p>然后再layout.ejs的<body>tag 中调用<code><%- body %></code></p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><!DOCTYPE <span class="meta-keyword">html</span>></span></span><br><span class="line"><span class="tag"><<span class="name">html</span>></span></span><br><span class="line"><span class="tag"><<span class="name">head</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">title</span>></span><span class="tag"></<span class="name">title</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"utf-8"</span>></span></span><br><span class="line"><span class="tag"></<span class="name">head</span>></span></span><br><span class="line"><span class="tag"><<span class="name">body</span>></span></span><br><span class="line"></span><br><span class="line"> Hello World</span><br><span class="line"></span><br><span class="line"> <%- body %></span><br><span class="line"><span class="tag"></<span class="name">body</span>></span></span><br><span class="line"><span class="tag"></<span class="name">html</span>></span></span><br></pre></td></tr></table></figure></li></ul><p><img src="https://i.loli.net/2020/12/28/4kNTJ9XGu1gYKyd.png" alt="demo2"></p><ul><li><p>知道了文件的调用之后,我们变可以再对应的文件中添加我们自己的逻辑,但是现在有一个问题,我们如何拿到我们的博客数据呢,如首页的博文列表,每篇博文的创建时间,内容,标题等等。Hexo提供了很多的api来获取这些信息,如在主页时,通过<code>page.posts</code>可以获得当前page的所有博文信息,<code>page.prev_link</code>可以跳转到上一页,可以帮助我们实现翻页逻辑。具体的信息可以查看<a href="https://hexo.io/zh-cn/docs/variables">Hexo官方文档</a></p><p>我们现在通过page.posts来获取主页博客列表,将博文标题打印出来:<br>index.ejs</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">ul</span>></span></span><br><span class="line"> <% page.posts.each(function(post, index) { %> </span><br><span class="line"> <span class="tag"><<span class="name">li</span>></span></span><br><span class="line"> <%= post.title %></span><br><span class="line"> <span class="tag"></<span class="name">li</span>></span></span><br><span class="line"> <% }) %></span><br><span class="line"> <span class="tag"></<span class="name">ul</span>></span></span><br><span class="line"><span class="tag"></<span class="name">div</span>></span></span><br></pre></td></tr></table></figure></li></ul><p><img src="https://i.loli.net/2020/12/28/ExncAgleBq91Nz3.png" alt="demo3"></p><p> 在了解如何获得数据和文件的调用之后,剩下的就是脑洞大开,打造属于自己独特的博客主题了。</p>]]></content>
<summary type="html"><hr>
<p>Hexo是一个很轻便简洁的博客框架,没有太多的学习难度,如果对于博客功能和样式没有太多要求,几乎只需要安装,学会如何创建和发布博客即可。<br>对于一个程序员来说,当对于下载的主题有定制化需求的时候,总感觉不如直接撸一个属于自己的主题,抱着这种想法,时隔很久之后又</summary>
<category term="前端开发" scheme="http://yulinliang.com/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
<category term="Hexo" scheme="http://yulinliang.com/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/Hexo/"/>
<category term="Hexo" scheme="http://yulinliang.com/tags/Hexo/"/>
<category term="Web" scheme="http://yulinliang.com/tags/Web/"/>
</entry>
<entry>
<title>Leetcode 1642 Furthest Building You Can Reach</title>
<link href="http://yulinliang.com/2020/12/14/Leetcode-1642-Furthest-Building-You-Can-Reach/"/>
<id>http://yulinliang.com/2020/12/14/Leetcode-1642-Furthest-Building-You-Can-Reach/</id>
<published>2020-12-15T04:50:03.000Z</published>
<updated>2020-12-15T04:51:29.667Z</updated>
<content type="html"><![CDATA[<h2 id="Question"><a href="#Question" class="headerlink" title="Question"></a>Question</h2><p>Leetcode <a href="https://leetcode.com/problems/furthest-building-you-can-reach/">1642 Furthest Building You Can Reach</a></p><h2 id="Solutions"><a href="#Solutions" class="headerlink" title="Solutions"></a>Solutions</h2><h3 id="Brute-Force-(Memory-Limit-Exceed)"><a href="#Brute-Force-(Memory-Limit-Exceed)" class="headerlink" title="Brute Force (Memory Limit Exceed)"></a>Brute Force (Memory Limit Exceed)</h3><p>This solution doesn’t pass tests, but it is also a good thought to help us improve our thinking ability.</p><p>The straightforward solution is to try all possible ways to move to the next building and calculate the furthest destination. Based on this idea, we can use iteration to solve this problem. </p><p>Our subproblem is to calculate the furthest destination from a specific building with some ladders and bricks. So we can define a function as follows:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">tryFurthestBuilding</span><span class="params">(<span class="keyword">int</span>[] heights, <span class="keyword">int</span> bricks, <span class="keyword">int</span> ladders, <span class="keyword">int</span> currentIndex)</span> </span>{</span><br><span class="line"> ...</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>The function returns the furthest building we can reach from <code>currentIndex</code> with <code>bricks</code> and <code>ladders</code>.</p><p>Here’s the stop condition of our iteration:</p><ol><li><code>currentIndex == heights.length -1</code> : no more building we can move.</li><li><code>ladders == 0 && bricks < heights[currentIndex + 1] - heights[currentIndex]</code>: we don’t have enough bricks and ladders to move to the next building.</li></ol><p>For each iteration, there are several situations:</p><ol><li><p>heights[currentIndex + 1] < heights[currentIndex]: we can always move to the next building.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (heights[currentIndex + <span class="number">1</span>] > heights[currentIndex]) {</span><br><span class="line"><span class="keyword">return</span> tryFurthestBuilding(heights, bricks, ladders, currentIndex + <span class="number">1</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>We have to use bricks or ladders to move to the next building. And we will try both methods, and treat the furthest(<code>Math.max</code>) building as the result. </p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span> destinationWithLadder = ladders > <span class="number">0</span> </span><br><span class="line"> ? tryFurthestBuilding(heights, bricks, ladders - <span class="number">1</span>, countMap, currentIndex + <span class="number">1</span>) </span><br><span class="line"> : currentIndex;</span><br><span class="line"><span class="keyword">int</span> destinationWithBricks = bricks > heights[currentIndex + <span class="number">1</span>] - heights[currentIndex] </span><br><span class="line"> ? tryFurthestBuilding(heights, bricks - heightDiff, ladders, countMap, currentIndex + <span class="number">1</span>) </span><br><span class="line"> : currentIndex;</span><br><span class="line"><span class="keyword">return</span> Math.max(destinationWithLadder, destinationWithBricks);</span><br></pre></td></tr></table></figure></li></ol><p>Optimization:</p><p>There might be some duplications, for example, the initial condition is as follows:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">heights = [6,7,8,9,14,12], bricks = 5, ladders = 1</span><br><span class="line">There're several methods to move the index 2:</span><br><span class="line"></span><br><span class="line">Iteration_A => Building 0 - Building 1(with a ladder) - Building 2(with a brick)</span><br><span class="line"> bricks = 4, ladders = 0, currentIndex = 2</span><br><span class="line"> </span><br><span class="line">Iteration_B => Building 0 - Building 1(with a brick) - Building 2(with a ladder)</span><br><span class="line"> bricks = 4, ladders = 0, currentIndex = 2</span><br></pre></td></tr></table></figure><p>As you can see, the furthest building we can reach from <code>Iteration_A</code> is the same as <code>Iteration_B</code>, we don’t need to calculate twice. So we can use a map to store all results for each iteration, and the key is based on the number of brick, ladder and current index.</p><p>We need to change our iteration function a little bit, we should pass our map to it.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">tryFurthestBuilding</span><span class="params">(<span class="keyword">int</span>[] heights, <span class="keyword">int</span> bricks, <span class="keyword">int</span> ladders, <span class="keyword">int</span> currentIndex, HashMap<String, Integer> destinationMap)</span> </span>{</span><br><span class="line"> ...</span><br><span class="line">} </span><br></pre></td></tr></table></figure><p>And here’s the code:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">furthestBuilding</span><span class="params">(<span class="keyword">int</span>[] heights, <span class="keyword">int</span> bricks, <span class="keyword">int</span> ladders)</span> </span>{</span><br><span class="line"> HashMap<String, Integer> destinationMap = <span class="keyword">new</span> HashMap<>();</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> tryFurthestBuilding(heights, bricks, ladders, <span class="number">0</span>, destinationMap);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">tryFurthestBuilding</span><span class="params">(<span class="keyword">int</span>[] heights, <span class="keyword">int</span> bricks, <span class="keyword">int</span> ladders, <span class="keyword">int</span> currentIndex, HashMap<String, Integer> destinationMap)</span> </span>{</span><br><span class="line"> String key = currentIndex + <span class="string">"-"</span> + bricks + <span class="string">"-"</span> + ladders;</span><br><span class="line"> <span class="comment">// We've already calculated this case before</span></span><br><span class="line"> <span class="keyword">if</span> (destinationMap.containsKey(key)) {</span><br><span class="line"> <span class="keyword">return</span> destinationMap.get(key);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// It's already the last building.</span></span><br><span class="line"> <span class="keyword">if</span> (currentIndex == heights.length - <span class="number">1</span>) {</span><br><span class="line"> destinationMap.put(key, currentIndex);</span><br><span class="line"> <span class="keyword">return</span> currentIndex;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">int</span> heightDiff = heights[currentIndex + <span class="number">1</span>] - heights[currentIndex];</span><br><span class="line"> <span class="comment">// We can always move to the next building without using any ladder or brick.</span></span><br><span class="line"> <span class="keyword">if</span> (heightDiff < <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">int</span> result = tryFurthestBuilding(heights, bricks, ladders, currentIndex + <span class="number">1</span>, destinationMap);</span><br><span class="line"> destinationMap.put(key, result);</span><br><span class="line"> <span class="keyword">return</span> result;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// Try to use ladder and bricks to move, and get the optimal result</span></span><br><span class="line"> <span class="keyword">int</span> useLadder = ladders > <span class="number">0</span> </span><br><span class="line"> ? tryFurthestBuilding(heights, bricks, ladders - <span class="number">1</span>, currentIndex + <span class="number">1</span>, destinationMap) </span><br><span class="line"> : currentIndex;</span><br><span class="line"> <span class="keyword">int</span> useBricks = bricks > heightDiff ? </span><br><span class="line"> tryFurthestBuilding(heights, bricks - heightDiff, ladders, currentIndex + <span class="number">1</span>, destinationMap) </span><br><span class="line"> : currentIndex;</span><br><span class="line"> destinationMap.put(key, Math.max(useLadder, useBricks));</span><br><span class="line"> <span class="keyword">return</span> Math.max(useLadder, useBricks);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>Unfortunately, the solution is not passed because of memory limit exceeded.</p><h3 id="Greedy"><a href="#Greedy" class="headerlink" title="Greedy"></a>Greedy</h3><p>The basic idea of this question is to use a ladder when moving to the next building requires much more bricks. We can use a priority queue, all movements(<code>heights[currentIndex + 1] - heights[currentIndex]</code>) require ladders or bricks will be added into the priority queue. The size of the pq is the number of ladders we have, which means all these movements we can use ladders to finish. </p><p>When pq is full, which means the ladders are not enough, then we try to use as less bricks as possible to finish a single movement, that’s the min element of our pq.</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">furthestBuilding</span><span class="params">(<span class="keyword">int</span>[] A, <span class="keyword">int</span> bricks, <span class="keyword">int</span> ladders)</span> </span>{</span><br><span class="line"> PriorityQueue<Integer> pq = <span class="keyword">new</span> PriorityQueue<>();</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < A.length - <span class="number">1</span>; i++) {</span><br><span class="line"> <span class="keyword">int</span> d = A[i + <span class="number">1</span>] - A[i];</span><br><span class="line"> <span class="keyword">if</span> (d > <span class="number">0</span>)</span><br><span class="line"> pq.add(d);</span><br><span class="line"> <span class="keyword">if</span> (pq.size() > ladders)</span><br><span class="line"> bricks -= pq.poll();</span><br><span class="line"> <span class="keyword">if</span> (bricks < <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">return</span> i;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> A.length - <span class="number">1</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="Complexity"><a href="#Complexity" class="headerlink" title="Complexity"></a>Complexity</h3><ul><li>We only use a priority queue to store <code>K</code> element, so the <code>space complexity</code> is <code>O(K)</code>.</li><li>The <code>time complexity</code> here is <code>O(NlogK)</code><ul><li><code>Iteration</code> - <code>O(N)</code></li><li>Maintain a priority queue - <code>O(NlogK)</code></li></ul></li></ul>]]></content>
<summary type="html"><h2 id="Question"><a href="#Question" class="headerlink" title="Question"></a>Question</h2><p>Leetcode <a href="https://leetcode.com/problem</summary>
<category term="Algorithm" scheme="http://yulinliang.com/categories/Algorithm/"/>
</entry>
<entry>
<title>移动开发 - 屏幕成像原理</title>
<link href="http://yulinliang.com/2020/12/10/%E7%A7%BB%E5%8A%A8%E5%BC%80%E5%8F%91-%E5%B1%8F%E5%B9%95%E6%88%90%E5%83%8F%E5%8E%9F%E7%90%86/"/>
<id>http://yulinliang.com/2020/12/10/%E7%A7%BB%E5%8A%A8%E5%BC%80%E5%8F%91-%E5%B1%8F%E5%B9%95%E6%88%90%E5%83%8F%E5%8E%9F%E7%90%86/</id>
<published>2020-12-11T07:12:58.000Z</published>
<updated>2020-12-11T07:13:50.439Z</updated>
<content type="html"><![CDATA[<p>在移动端开发中,我们经常会提到一个FPS优化,大家可能都知道fps越高,app给人的视觉流畅性越好。正好借此机会,梳理并且整理一下自己对屏幕渲染成像的一些理解。</p><h3 id="帧率-Frame-Rate-和刷新率-Refresh-Rate"><a href="#帧率-Frame-Rate-和刷新率-Refresh-Rate" class="headerlink" title="帧率(Frame Rate)和刷新率(Refresh Rate)"></a>帧率(Frame Rate)和刷新率(Refresh Rate)</h3><p>在解释成像原理前有两个概念我们需要理解一下:帧率和刷新率。</p><p>众所周知,显示器上的每一帧画面是通过cpu计算之后再由gpu渲染得来的。gpu完成渲染时,会将渲染结果放到屏幕的帧缓冲区(frame buffer)中,视频控制器会不断的从帧缓冲区中读取数据,递交给显示器进行显示。</p><ol><li><p><strong>帧率</strong></p><p><img src="https://i.loli.net/2020/12/11/MWaz1AmuIJDkZtY.png" alt="帧率"></p><p>帧率就是指cpu和gpu生成一帧画面的速率,单位是fps,如60fps,就代表每秒能生成60帧。我们在做移动端优化时就是需要提高帧率,从而避免出现卡顿效果。</p></li><li><p><strong>刷新率</strong></p><p><img src="https://i.loli.net/2020/12/11/IoZrNCuQSpLzFbB.png" alt="refresh rate"></p><p>顾名思义,刷新率指的就是屏幕进行刷新页面图像的速率,单位是Hz,如60Hz代表的就是每秒屏幕刷新60帧,通常来说对于同一台设备而言,刷新率是固定不变的。</p></li><li><p><strong>帧率 > 刷新率</strong></p><p>当帧率大于刷新率时,意味着频率的刷新频率过慢,可能出现的情况就是当一帧在屏幕上的绘制还没有结束时,新生成的一帧图像就覆盖了正在显示的图像,从而两帧或者多帧被同时显示在同一个画面上。如下图所示:</p></li><li><p><strong>帧率 < 刷新率</strong></p><p>当帧率过慢时,可能会出现同一帧图像在多次刷新中被使用。如果帧率无法跟上程序运行速度,就会给人一种视觉上的卡顿感。比如在打LOL时,帧率过低会让人感觉游戏人物行动不是很流畅,技能偏移较大。</p><p>那有什么方法能够保证让帧率和刷新率尽可能同步呢?这就引入了VSync,垂直同步信号。</p></li></ol><h3 id="VSync-垂直同步信号"><a href="#VSync-垂直同步信号" class="headerlink" title="VSync 垂直同步信号"></a>VSync 垂直同步信号</h3><p>垂直同步信号的主要时用来同步CPU, GPU和显示器的。一般来说,显示器的图像显示是由CPU,GPU和显示器协同合作完成的。CPU主要用于数学和逻辑处理,GPU主要执行图形相关操作,最终确定显示时各个像素点色值。</p><p><img src="https://i.loli.net/2020/12/11/CyYarom1AGpgTE2.png" alt="vsync"></p><p>显示器在绘制显示一帧后,会准备下一帧的绘制,此时显示器会发出一个垂直同步信号,CPU在接收到这个信号之后就开始准备新一帧的计算,显示内容计算完成之后转交给GPU进行渲染。渲染完成之后会被放入帧缓冲区,然后视频控制器就能够根据同步信号从缓冲区中取出数据递交给显示器展示。</p><p>以上就是对于屏幕成像的一些基本理解,从中我们可以看出,CPU和GPU对于保证页面性能来说都是非常重要的,不管哪个阻碍了显示流程,都会造成掉帧现象,这就是为什么我们需要不断对CPU和GPU进行优化的原因。</p>]]></content>
<summary type="html"><p>在移动端开发中,我们经常会提到一个FPS优化,大家可能都知道fps越高,app给人的视觉流畅性越好。正好借此机会,梳理并且整理一下自己对屏幕渲染成像的一些理解。</p>
<h3 id="帧率-Frame-Rate-和刷新率-Refresh-Rate"><a href="#帧</summary>
<category term="移动开发" scheme="http://yulinliang.com/categories/%E7%A7%BB%E5%8A%A8%E5%BC%80%E5%8F%91/"/>
</entry>
<entry>
<title>Implement a flutter chat app with Firebase</title>
<link href="http://yulinliang.com/2020/12/09/Implement%20a%20flutter%20chat%20app%20with%20Firebase/"/>
<id>http://yulinliang.com/2020/12/09/Implement%20a%20flutter%20chat%20app%20with%20Firebase/</id>
<published>2020-12-10T06:12:24.000Z</published>
<updated>2020-12-11T00:02:59.702Z</updated>
<content type="html"><![CDATA[<h4 id="Firebase-setup"><a href="#Firebase-setup" class="headerlink" title="Firebase setup"></a>Firebase setup</h4><p>We are going to use Firebase authentication to implement our log in system, then all messages will be stored in Cloud Database. So we need to set up Firebase first.</p><ul><li><p>Add a new project in Firebase: <a href="https://console.firebase.google.com/u/0/">linked</a></p></li><li><p><strong>Register your app with Firebase</strong> and add Firebase configurations to your app.</p></li><li><p>Install cloud_firestore into your flutter project: <a href="https://pub.dev/packages/cloud_firestore">cloud_firestore pub dev</a></p></li></ul><h4 id="Cloud-Firestore-APIs"><a href="#Cloud-Firestore-APIs" class="headerlink" title="Cloud Firestore APIs"></a>Cloud Firestore APIs</h4><ul><li><p><a href="https://firebase.flutter.dev/docs/firestore/usage">official document</a></p></li><li><p><strong>Firestore data model</strong></p><ul><li>The <strong>document</strong> is a piece of data, it is the unit of storage, which contains multiple fields and values.</li><li>The <strong>collection</strong> is more like a table, which contains a list of documents.</li><li>Obviously, collection can be nested inside of a document.</li></ul></li><li><p><strong>Database structure</strong></p><ul><li>Here we mainly focus on the real time chat room implementation, just to simplify our situation, let’s assume we could have multiple users, but for each user, they only have one chat room with a list of real time messages. </li><li>Therefore we can have a Users collection, which contains a list of user document. Each user document point to a Message collection, all messages are stored inside the Message collection. The structure is as follows:</li></ul></li></ul><p><img src="https://i.loli.net/2020/12/10/1HIO3DrCNkRFhJY.png" alt="database"></p><ul><li><p><strong>One-time Read</strong></p><ul><li>Call the <code>Query.get</code> or <code>DocumentReference.get</code></li></ul></li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">CollectionReference users = FirebaseFirestore.instance.collection('users');</span><br><span class="line"></span><br><span class="line">return FutureBuilder<DocumentSnapshot>(</span><br><span class="line"> future: users.doc(documentId).get(),</span><br><span class="line"> builder:</span><br><span class="line"> (BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {</span><br><span class="line"></span><br><span class="line"> if (snapshot.hasError) {</span><br><span class="line"> return Text("Something went wrong");</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (snapshot.connectionState == ConnectionState.done) {</span><br><span class="line"> Map<String, dynamic> data = snapshot.data.data();</span><br><span class="line"> return Text("Full Name: ${data['full_name']} ${data['last_name']}");</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> return Text("loading");</span><br><span class="line"> },</span><br><span class="line">);</span><br></pre></td></tr></table></figure><ul><li><p><strong>Realtime changes</strong></p><ul><li>Fortunately, Firestore provides us a convenient way to listen to the real time changes. <code>CollectionReference</code> and <code>DocumentReference</code> both provide a <code>snapshots</code> method to help observe any subsequent changes to the collection or document. Which returns a <code>Stream</code>, so we can easily use a <code>StreamBuilder</code> to manage the streams state.</li></ul></li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">StreamBuilder(</span><br><span class="line"> stream: Firestore.instance.collection('User/j42RaSRUQ7c6ldQe3hjQ/Messages').snapshots(),</span><br><span class="line"> builder: (ctx, snapshot) {</span><br><span class="line"> if (snapshot.hasError) {</span><br><span class="line"> return Text("Something went wrong");</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> if (snapshot.connectionState == ConnectionState.waiting) {</span><br><span class="line"> return Text("Loading");</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> var data = snapshot.data.documents;</span><br><span class="line"> print(data);</span><br><span class="line"> return ListView.builder(</span><br><span class="line"> itemCount: data.length,</span><br><span class="line"> itemBuilder: (ctx, index) => Text('text')</span><br><span class="line"> ); </span><br><span class="line"> },</span><br><span class="line">)</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><h4 id="Firebase-setup"><a href="#Firebase-setup" class="headerlink" title="Firebase setup"></a>Firebase setup</h4><p>We are going to use Fi</summary>
<category term="Flutter learning notes" scheme="http://yulinliang.com/categories/Flutter-learning-notes/"/>
</entry>
<entry>
<title>来美工作一年半回顾</title>
<link href="http://yulinliang.com/2020/12/08/blog/"/>
<id>http://yulinliang.com/2020/12/08/blog/</id>
<published>2020-12-09T03:46:15.000Z</published>
<updated>2020-12-09T04:59:16.084Z</updated>
<content type="html"><![CDATA[<h2 id="萌芽"><a href="#萌芽" class="headerlink" title="萌芽"></a>萌芽</h2><p>2016年开始,突然萌生了想要出国留学的想法。以前总感觉留学对于我这种家境及其一般的人来说是如此遥不可及,但是从提交了gre报名费的那一刻开始,就觉得梦想仿佛也可能会成为现实。于是开始了每天早上5点起床学习英语的苦旅,对于一个在腾讯工作的程序员来说,基本除了“早上”以外就完全抽不出任何空闲时间了。坚持了大半年,托福刷了4,5次也还是上不了100,最后拿着96分的成绩开始了申请之旅,也很幸运的得到了usc和其他几个offer。</p><h2 id="启程"><a href="#启程" class="headerlink" title="启程"></a>启程</h2><p>2017年8月,开始了留学之旅,抱着对美帝的幻想离开了父母家人。<br>usc生活的两年,基本上都是在图书馆刷题自习。作为工程性质的程序员来说,我感觉研究生课程和本科差别不大,而且因为我已经确定毕业之后还是继续iOS的开发工作,所以我对课程的要求就只是应付好作业和考试,其余时间就是刷题准备找工作。</p><p>本科基本上没有接触过算法,唯一的“算法”课程就是数据结构,当时也只是停留在应付考试的水平,还记得当时上机考试,怎么都没法实现。或许是因为在腾讯磨练了四年,再次接触算法觉得实现很容易,在刷题时只要理清算法思路,编程实现完全没有问题,慢慢的也对算法产生了兴趣,开始享受“AC”掉hard难度的成就感。也开始了leetcode的contest之旅,从2,300名稳定到前50,最高的时候拿到第2名,感觉是算法之旅的高光时刻了吧,再次感谢我大腾讯的高强度工作。</p><h2 id="实习招聘"><a href="#实习招聘" class="headerlink" title="实习招聘"></a>实习招聘</h2><p>因为有腾讯的三年工作经验,而且有手机QQ这种大流量的产品开发经验,我一度以为面试会拿到手软。结果从收到google的拒信开始就被啪啪打脸,虽然有一点遗憾,但是也并没有感觉特别难过。最终只收到了Pocket Gems和LinkedIn的面试,运气不错的都拿到了offer。出于对大公司的向往和好奇,自然而然的选择了LinkedIn的实习。</p><p>一直很感谢LinkedIn的这一段经历,遇到了很多非常帮助我的国人前辈们。因为不是native speaker,一直对交流存在着恐惧,感觉常常不是很自信。但是组内的国人前辈们常常开导鼓励我,而且非常幸运的遇到了一个非常nice的印度manager,顺利的完成了实习生活,也拿到了return offer,这也预示着最后一年的研究生生活对于找工作的压力大大减少。</p><h2 id="充值信仰"><a href="#充值信仰" class="headerlink" title="充值信仰"></a>充值信仰</h2><p>在最后一年的找工作之旅中,因为有LinkedIn的return offer,我投递的公司也就只有google和facebook。Facebook还是一如既往的高冷,从一而终的不给面试机会,但是这一次顺利拿到了google的面试。于是开始了一个月疯狂的准备。</p><p>4轮面试顺利发挥,每一轮的“暗坑”和“考点”都成功get,所以在面试结束之后立刻就觉得稳了。在等了两周之后,hr通知面试通过,不过意外的是她主动给了我L4的职级,我始终还记得那一刻的喜悦,感觉就像是“梦”照进了现实。</p><h2 id="职场起伏"><a href="#职场起伏" class="headerlink" title="职场起伏"></a>职场起伏</h2><p>2019年入职youtube,本来对未来充满憧憬,结果还是被现实狠狠打脸。工作内容还算顺心,工作半年就成功拿到2个peer bonus和2个spot bonus,但是工作氛围一直觉得无法融入。可能由于对英语的不自信,所以会不自觉的想要去回避一切的组内social活动,然后开始自然而然的觉得和组内同事渐行渐远,对比以前在国内和同事达成一篇,这个落差确实无法接受。另外一方面manager略坑,关系较好的同事工作不到一年就转组离职,导致我也开始想要transfer out。最终在今年5月份离开了这个组,去到了grpc team。</p><p>原本以为来到新组,作为唯一一个objective c的owner,可以有很大的发展空间,也可以学到很多东西。结果大半年时间过去了,还是做一些零散的小事。感觉可能是之前找工作太过于顺利,所有曾经以为的不可能都实现了,还被意外升职,花光了我这两年的人品吧。感觉虽然来到自己信仰的公司,但是确实工作5年来最低谷的两年。</p><p>2020这魔幻的一年只剩下最后一个月了,照旧对2021满怀期待。工作不如意不要放弃,生活还是得继续,继续加油,继续憧憬2021,愿2021能善待我以及所有这一年中不顺心的朋友们吧。</p>]]></content>
<summary type="html"><h2 id="萌芽"><a href="#萌芽" class="headerlink" title="萌芽"></a>萌芽</h2><p>2016年开始,突然萌生了想要出国留学的想法。以前总感觉留学对于我这种家境及其一般的人来说是如此遥不可及,但是从提交了gre报名费的那一刻开</summary>
<category term="三省吾身" scheme="http://yulinliang.com/categories/%E4%B8%89%E7%9C%81%E5%90%BE%E8%BA%AB/"/>
</entry>
</feed>