-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsearch.xml
More file actions
260 lines (205 loc) · 48.1 KB
/
Copy pathsearch.xml
File metadata and controls
260 lines (205 loc) · 48.1 KB
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title><![CDATA[基于梯度的优化方法]]></title>
<url>http://vectorliu.com/2017/08/11/algorithm-gradient-descent-method/</url>
<content type="html"><![CDATA[<h2 id="最优化问题描述"><a href="#最优化问题描述" class="headerlink" title="最优化问题描述"></a>最优化问题描述</h2><p>最优化问题广泛存在于学术研究和工程实际中。一个典型的最优化问题通常包括自变量、优化目标函数以及约束条件等等。机器学习作为一种热门的工程应用,通常包括模型、目标函数以及优化方法三个部分。一般而言,优化通常使用较为成熟的方法。本文重点介绍一些经典的优化算法,当目标函数是凸函数时,这些方法往往能得到全局最优解。</p>
<p>从数值迭代算法的角度考虑,不妨记当前时刻的估计为$\mathbf{x}_k$,下一时刻的估计记为$\mathbf{x}_{k+1}$,优化算法的一般形式记为:<br>$$\mathbf{x}_{k+1} = \mathbf{x}_k + \alpha \Delta \mathbf{x}$$<br>其中$\alpha > 0$是步长,$\Delta \mathbf{x}$为迭代方向,各种优化方法的区别在于怎么选定迭代方向以及步长。根据原理不同,可将其总结为两大类:即一阶算法和二阶算法。一阶算法主要是梯度下降相关算法,二阶算法主要是牛顿法相关算法。<br><a id="more"></a></p>
<p>根据泰勒公式,可以将$f(\mathbf{x}_{k+1})$在点$\mathbf{x}_k$处展开为:<br>$$<br>\begin{equation}<br>f(\mathbf{x}_{k+1}) = f(\mathbf{x}_k) + \alpha \mathbf{g}_k^T \Delta\mathbf{x} + \frac{\alpha^2}{2} \Delta \mathbf{x}^T \mathbf{H}_k \Delta \mathbf{x} + \mathcal{o}(||\Delta \mathbf{x}||^2)<br>\end{equation} \tag{1}<br>$$<br>上式中,$\mathbf{g}_k = \frac{\partial f}{\partial \mathbf{x}}(\mathbf{x}_k)$,表示一阶梯度向量,而$\mathbf{H}_k$表示海森矩阵(Hessian matrix),$\mathcal{o}(\cdot)$表示参数的高阶无穷小。</p>
<h2 id="一阶算法"><a href="#一阶算法" class="headerlink" title="一阶算法"></a>一阶算法</h2><h3 id="梯度下降算法"><a href="#梯度下降算法" class="headerlink" title="梯度下降算法"></a>梯度下降算法</h3><p>对于任意函数,我们不妨取式$1$中右边的前两项,则可以得到:<br>$$<br>\begin{equation}<br>f(\mathbf{x}_{k+1}) \approx f(\mathbf{x}_k) + \alpha \mathbf{g}_k^T \Delta\mathbf{x}<br>\end{equation} \tag{2}<br>$$<br>由于我们的目标是最小化$f(\mathbf{x})$,因此一个显然的迭代方向选择为$\Delta \mathbf{x} = -\mathbf{g}_k$。根据向量内积,可以发现该方向是函数值下降最快的方向,据此可以得到梯度下降算法(又称最速下降法)如下:<br> $$\mathbf{x}_{k+1} = \mathbf{x}_k - \alpha_k \mathbf{g}_k$$<br>考虑到上述推导依赖于泰勒展开近似,梯度下降算法在实际使用还需要考虑步长$\alpha$的选择。步长如果选取的过大,则可能会导致函数值变大;如果选取的过小,则可能会导致收敛很慢。实际中通常选择衰减的步长,以符合误差的衰减。或者通过line search对步长进行进一步的优化:<br>$$<br>\alpha^\ast = \underset{\alpha}{\operatorname{argmin}} {f(\mathbf{x}_k - \alpha \mathbf{g}_k)}<br>$$<br>梯度下降算法适用于任何可微分的函数,并且可以求得该类函数的局部极小值。当函数不是处处可微时,通过次梯度下降算法(subgradient descent method)来求解,典型的该类函数是绝对值函数,次梯度下降算法的分析与梯度下降类似。</p>
<p>在机器学习领域,梯度下降算法的经典实现是随机梯度下降算法(Stochastic Gradient Descent,SGD),SGD通过随机采样一个或者一批(batch)样本,并计算其损失函数(全局损失函数可以拆分为所有样本损失函数之和)对应的梯度,以更新分类/回归模型的参数。在更大规模数据集中,SGD往往比经典的梯度下降收敛更快。</p>
<h3 id="共轭梯度下降算法"><a href="#共轭梯度下降算法" class="headerlink" title="共轭梯度下降算法"></a>共轭梯度下降算法</h3><p>梯度方向虽然是函数值下降最快的方向,但是在实际使用中会存在以下问题:1)在最优解附近收敛变慢;2)如果函数存在特殊的梯度变化,会出现“之字形”走法(zigzag现象),导致收敛效率低。这类问题出现的原因在于在收敛过程中,梯度序列${\mathbf{g}_0, …, \mathbf{g}_{n-1}}$不是完全线性独立的,导致搜索的过程可能出现“undo”和“redo”现象,即单一方向的搜索没有走到尽头。假设仍然采用一阶算法的基本形式,在如下更新率下:<br>$$<br>\mathbf{x}_{k+1} = \mathbf{x}_{k} + \alpha_k \mathbf{d}_k<br>$$<br>为确保单一方向搜索到了尽头,则需要满足如下约束条件:<br>$$<br>\mathbf{g}_{k+1}^T \mathbf{d}_k = 0 \tag{3}<br>$$<br>根据上式可以利用line search最小化$f(\mathbf{x}_{k} + \alpha \mathbf{d}_k)$得到最优的步长,本质上该步长代表了误差$\mathbf{e}_k = \mathbf{x}^\ast - \mathbf{x}_k$在当前方向$\mathbf{d}_k$上的投影长度。如果可以构建一组线性独立的基${\mathbf{d}_0, …, \mathbf{d}_{n-1}}$,将误差$\mathbf{e}_k$投影到每个方向上,则可以避免“undo”和“redo”现象。以上分析表述了共轭梯度下降算法(Conjugate Gradient Descent,CGD)的基本思想。</p>
<p>循一般套路,本文先针对特殊的二次规划问题利用CGD给出确定优化算法,然后将其推广到一般的函数最小化问题。考虑如下标准无约束二次规划问题:<br>$$<br>\min\limits_{\mathbf{x} \in \mathbb{R}^n}{f(\mathbf{x}) = \frac{1}{2}\mathbf{x}^T \mathbf{H} \mathbf{x} - \mathbf{b}^T \mathbf{x}}<br>$$<br>随机选定初始值$\mathbf{x}_0$,并计算当前梯度$\mathbf{g}_0 = \mathbf{H}\mathbf{x}_0 - \mathbf{b}$,令<br>$$<br>\mathbf{d}_0 = -\mathbf{g}_0<br>$$<br>可以得到$\mathbf{x}_1 = \mathbf{x}_0 + \alpha_0 \mathbf{d}_0$。根据梯度表达式和更新公式可得$\mathbf{g}_{1} = \mathbf{g}_{0} + \alpha_0 \mathbf{H} \mathbf{d}_0$。根据式(3),可以计算得到:<br>$$<br>\alpha_0 = -\frac{\mathbf{g}_0^T \mathbf{d}_0}{\mathbf{d}_0^T\mathbf{H}\mathbf{d}_0} \tag{4}<br>$$<br>至此我们得到了新的梯度向量$\mathbf{g}_1$,根据<a href="https://en.wikipedia.org/wiki/Gram–Schmidt_process" target="_blank" rel="external">Gram-Schmidt正交化方法</a>的思想,我们希望迭代构造一组正交的基底,便于对误差进行分解。如果按照一般的正交化套路构造了一组基底${\mathbf{d}_0, …, \mathbf{d}_{n-1}}$,则可以得到在$\mathbf{d}_k$上误差的投影长度为:$\alpha_k = \frac{\mathbf{d}_k^T \mathbf{e}_k}{\mathbf{d}_k^T \mathbf{d}_k}$。该种构造方法下,计算每个方向上的投影长度将需要知道$\mathbf{e}_k = \mathbf{x}^\ast - \mathbf{x}_k$的信息,构成了一个先有鸡还是先有蛋的问题。幸运的是,虽然不知道$\mathbf{e}_k$但是很容易得到:<br>$$<br>\mathbf{H} \mathbf{e}_k = \mathbf{H}(\mathbf{x}^\ast - \mathbf{x}_k) = \mathbf{b} - \mathbf{H}\mathbf{x}_k = -\mathbf{g}_k<br>$$<br>上式启发我们使用一种新的“正交”基底,以使得误差可以通过当前梯度来反映。具体地,通过构造一组$H$-共轭(H-Conjugate,H矩阵对称正定)的基底,即:<br>$$<br>\mathbf{d}_i^T \mathbf{H} \mathbf{d}_j = 0, \forall i,j = 0, …, n-1, i \neq j<br>$$<br>在该组基底下,我们接着式(4)构造新的搜索方向$\mathbf{d}_1$,根据$\mathbf{d}_1^T \mathbf{H} \mathbf{d}_0 = 0$,并结合$\mathbf{d}_1 = -\mathbf{g}_1 + \beta_0 \mathbf{d}_0$,可以解出:<br>$$<br>\beta_0 = \frac{\mathbf{g}_1^T\mathbf{H}\mathbf{d}_0}{\mathbf{d}_0^T\mathbf{H}\mathbf{d}_0} = \frac{\mathbf{g}_1^T \mathbf{g}_1}{\mathbf{g}_0^T \mathbf{g}_0}<br>$$<br>上述算法迭代进行下去即可得到整个CGD算法,总结针对二次规划的CGD算法,可以发现如下事实:</p>
<ol>
<li>存在如下正交以及$H$-共轭关系:$$\mathbf{g}_i^T\mathbf{g}_j = 0, \mathbf{d}_i^T \mathbf{H} \mathbf{d}_j = 0, \forall i,j = 0, …, n-1, i \neq j$$</li>
<li>对于正定二次规划问题,CGD可以在n步迭代后得到最优解,即$\mathbf{x}_n = \mathbf{x}^\ast$;</li>
<li>与GD相比,针对二次规划的CGD算法也只需要使用一阶梯度信息,增加的计算量不大,但是大大加速了GD算法的收敛,达到了确定步数的收敛。</li>
</ol>
<p>考虑到对任意函数进行二阶展开(参见式(1)),可以将CGD推广到任意函数最小化问题,得到如下Fletcher-Reeves算法:</p>
<blockquote>
<ol>
<li>随机选择初始点$\mathbf{x}_0$;</li>
<li>计算初始点梯度向量:$\mathbf{d}_0 \leftarrow -\mathbf{g}_0$;</li>
<li>循环$k = 0,1,…,n-1$,进行如下操作:<ul>
<li>通过line search得到最小化$f(\mathbf{x}_k + \alpha \mathbf{d}_k)$的$\alpha_k$;</li>
<li>$\mathbf{x}_{k+1} \leftarrow \mathbf{x}_k + \alpha_k \mathbf{d}_k$;</li>
<li>$\beta_k \leftarrow \frac{||\mathbf{g}_{k+1}||^2}{||\mathbf{g}_k||^2}$;</li>
<li>$\mathbf{d}_{k+1} \leftarrow -\mathbf{g}_k + \beta_k \mathbf{d}_k$;</li>
</ul>
</li>
<li>$\mathbf{x}_0 \leftarrow \mathbf{x}_n$;</li>
<li>检查终止条件,如不满足,则跳到步骤2。</li>
</ol>
</blockquote>
<p>Fletcher-Reeves算法通过嵌套实现,每一个外层循环的第一步本质上都是梯度下降算法,剩余的$n-1$步可以保证函数值不会增加,因此其收敛可以很容易通过梯度下降算法证明。CGD算法仅仅使用了一阶梯度信息,但是大大加快了收敛速度,是针对任意函数的一个通用性强的高效优化算法。</p>
<h2 id="二阶算法"><a href="#二阶算法" class="headerlink" title="二阶算法"></a>二阶算法</h2><p>二阶算法利用二阶展开来近似任意函数,即取式(1)右边的前三项,可得:<br>$$<br>\begin{equation}<br>f(\mathbf{x}_{k+1}) \approx f(\mathbf{x}_k) + \alpha \mathbf{g}_k^T \Delta\mathbf{x} + \frac{\alpha^2}{2} \Delta\mathbf{x}^T \mathbf{H}_k\Delta\mathbf{x}<br>\end{equation} \tag{4}<br>$$</p>
<h3 id="牛顿法"><a href="#牛顿法" class="headerlink" title="牛顿法"></a>牛顿法</h3><p>将式(4)看成一个以$\alpha\Delta\mathbf{x}$为参数的函数,最小化该函数等价于求梯度为零的点,即:<br>$$<br>\mathbf{H}_k (\alpha\Delta\mathbf{x}) + \mathbf{g}_k = 0<br>$$<br>从而可以得到下一步迭代的最优增量为:$\alpha\Delta\mathbf{x} = -\mathbf{H}_k^{-1} \mathbf{g}_k$。因此牛顿法可以总结为以下表达式:<br>$$<br>\mathbf{x}_{k+1} = \mathbf{x}_k - \mathbf{H}_k^{-1} \mathbf{g}_k<br>$$<br>从上式可以看出,牛顿法无需单独计算步长$\alpha_k$(也可以通过line search搜索最优的步长,得到一种改进的牛顿法),但是需要同时使用目标函数在当前点的一阶和二阶导数的信息,使得单步迭代的计算复杂度提升为$\mathcal{O}(n^2)$。进一步地,牛顿法还需要计算Hessian矩阵的逆,使得复杂度进一步提升为$\mathcal{O}(n^3)$。由于使用了二阶导数的信息,牛顿法可以一步得到二次规划问题的最优解。对于可以用二阶近似的函数,牛顿法也可以很快地找到最优解的近似。为了克服牛顿法需要计算Hessian矩阵逆的麻烦,出现了各种各样的拟牛顿法(Quasi-Newton method),不同的拟牛顿法的区别在于对Hessian矩阵及其逆的不同计算方法。在下面的介绍中,我们记Hessian矩阵$\mathbf{H}_k$的近似逆矩阵为$\mathbf{V}_k$。</p>
<h3 id="拟牛顿法:SR1算法"><a href="#拟牛顿法:SR1算法" class="headerlink" title="拟牛顿法:SR1算法"></a>拟牛顿法:SR1算法</h3><p>SR1是Symmetric Rank One correction的简写。拟牛顿法的核心在于迭代估计Hessian矩阵$\mathbf{H}_k$或其逆矩阵。对函数的梯度在当前点进行一阶展开,则有:<br>$$<br>\mathbf{H}_k (\mathbf{x}_{k+1} - \mathbf{x}_{k}) = \mathbf{g}_{k+1} - \mathbf{g}_k<br>$$<br>便于分析,记$\mathbf{p}_k = \mathbf{x}_{k+1} - \mathbf{x}_{k}$,$\mathbf{q}_k = \mathbf{g}_{k+1} - \mathbf{g}_{k}$,由于$\mathbf{p}_k$、$\mathbf{q}_k$在选定下一迭代点后都可以得到,因此上式给出了关于未知量$\mathbf{H}_k$的一个方程。如果直接采用逆矩阵$\mathbf{V}_k$,则上式为:<br>$$<br>\mathbf{V}_k \mathbf{q}_{k} = \mathbf{p}_{k} \tag{5}<br>$$<br>同样地,我们<strong><em>以二次规划为例</em></strong>分析算法流程,再将其推广到一般函数。对于二次函数,Hessian矩阵为定值,因此在$k$次迭代后,有如下表达式:<br>$$<br>\mathbf{V}_{k+1} [\mathbf{q}_{0}, \mathbf{q}_{1}, …, \mathbf{q}_{k}] = [\mathbf{p}_{0}, \mathbf{p}_{1}, …, \mathbf{p}_{k}] \tag{6}<br>$$<br>可以发现,从$\mathbf{V}_{k}$到$\mathbf{V}_{k+1}$,对于估计$\mathbf{V}$而言,只是增加了一组信息$[\mathbf{q}_{k}, \mathbf{p}_{k}]$,因此,一种自然的迭代思路是给当前估计增添一个秩为1的矩阵,SR1的迭代如下,<strong><em>SR1可以保证矩阵始终是对称</em></strong>的:<br>$$<br>\mathbf{V}_{k+1} = \mathbf{V}_k + a_k \mathbf{z}_k \mathbf{z}_k^T, \quad a_k \in \mathbb{R}, \quad \mathbf{z}_k \in \mathbb{R}^n<br>$$<br>利用待定系数法即可得到$a_k$和$\mathbf{z}_k$,最终结果如下:<br>$$<br>\mathbf{V}_{k+1} = \mathbf{V}_k + \frac{(\mathbf{p}_k - \mathbf{H}_k \mathbf{q}_k)(\mathbf{p}_k - \mathbf{H}_k \mathbf{q}_k)^T}{\mathbf{q}_k^T (\mathbf{p}_k - \mathbf{H}_k \mathbf{q}_k)} \tag{7}<br>$$<br>据此可以得到SR1算法的流程如下:</p>
<blockquote>
<ol>
<li>随机选择初始点$\mathbf{x}_0$和初始Hessian逆矩阵估计$\mathbf{V}_0$;</li>
<li>计算当前点梯度向量:$\mathbf{g}_0$;</li>
<li>通过line search寻找最优的步长$\alpha$;</li>
<li>更新得到$\mathbf{x}_{k+1}$以及梯度,并计算$\mathbf{p}_k$和$\mathbf{q}_k$;</li>
<li>根据式(7)计算更新$\mathbf{V}_{k}$;</li>
<li>检查终止条件,如不满足,则跳到步骤3。</li>
</ol>
</blockquote>
<p>SR1算法可以保证近似的Hessian逆矩阵始终是对称的,但无法保证矩阵是正定的(正定矩阵可以保证每一步迭代函数值都是减小的)。同时,迭代计算过程中可能会存在分母为零的情况,导致数值计算失效。</p>
<h3 id="拟牛顿法:DFP算法"><a href="#拟牛顿法:DFP算法" class="headerlink" title="拟牛顿法:DFP算法"></a>拟牛顿法:DFP算法</h3><p>DFP算法的全称是Davidon–Fletcher–Powell算法,是史上第一个拟牛顿法。DFP最早由Davidon于1959年提出,经由Fletcher和Powell于1963年改进完善得到。DFP的核心思想也是迭代估计$\mathbf{V}_k$。不同于SR1算法,DFP在确保$\mathbf{V}_k$对称的同时,同时保证矩阵是正定的,使得函数始终递减。类似于SR1,DFP通过添加秩2的矩阵迭代修改$\mathbf{V}_k$(通过加上两个秩为1的矩阵实现),通过待定系数确定迭代公式。此处省略具体的推导过程,给出DFP算法的流程如下:</p>
<blockquote>
<ol>
<li>初始化选择$\mathbf{V}_0$为一个对称正定矩阵,随机选择初始点$\mathbf{x}_0$并计算梯度$\mathbf{g}_0$,$k = 0$;</li>
<li>设置搜索方向为$\mathbf{d}_k = -\mathbf{V}_k \mathbf{g}_k$;</li>
<li>通过line search搜索最优的步长$\alpha$;</li>
<li>得到$\mathbf{x}_{k+1}$,计算当前梯度和$\mathbf{p}_k$、$\mathbf{q}_k$;</li>
<li>更新$\mathbf{V}_{k+1} = \mathbf{V}_k + \frac{\mathbf{p}_k \mathbf{p}_k^T}{\mathbf{p}_k^T \mathbf{q}_k} - \frac{\mathbf{V}_k \mathbf{q}_k \mathbf{q}_k^T \mathbf{V}_k}{\mathbf{q}_k^T \mathbf{V}_k \mathbf{q}_k}$;</li>
<li>设置$k = k + 1$,跳到步骤2。</li>
</ol>
</blockquote>
<h3 id="拟牛顿法:BFGS算法"><a href="#拟牛顿法:BFGS算法" class="headerlink" title="拟牛顿法:BFGS算法"></a>拟牛顿法:BFGS算法</h3><p>BFGS算法的全称是Broyden–Fletcher–Goldfarb–Shanno算法,是当前使用的主流优化算法,可以通过MATLAB的fminunc函数直接调用。BFGS算法可以看成是DFP的对偶实现,着眼于估计Hessian矩阵而不是其逆矩阵,再利用Sherman-Morrison矩阵求逆公式计算Hessian矩阵的逆。为保持本文的完整性,在此给出该逆矩阵公式。</p>
<blockquote>
<p><strong><em>Sherman-Morrison矩阵求逆公式</em></strong><br>假定方阵$\mathbf{A}$和向量$\mathbf{\mu}$、$\mathbf{\nu}$满足$1 + \mathbf{\nu}^T \mathbf{A}^{-1} \mathbf{\mu} \neq 0$,则:<br>$$<br>(\mathbf{A} + \mathbf{\mu}\mathbf{\nu}^T)^{-1} = \mathbf{A}^{-1} - \frac{\mathbf{A}^{-1} \mathbf{\mu} \mathbf{\nu} \mathbf{A}^{-1}}{1 + \mathbf{\nu}^T \mathbf{A}^{-1} \mathbf{\mu}}<br>$$</p>
</blockquote>
<p>考虑到$\mathbf{H}_k$和$\mathbf{V}_k$互为逆矩阵,根据DFP算法的对偶可以得到$\mathbf{H}_k$的更新满足如下表达式:<br>$$<br>\mathbf{H}_{k+1} = \mathbf{H}_k + \frac{\mathbf{q}_k \mathbf{q}_k^T}{\mathbf{q}_k^T \mathbf{p}_k} - \frac{\mathbf{H}_k \mathbf{p}_k \mathbf{p}_k^T \mathbf{H}_k}{\mathbf{p}_k^T \mathbf{H}_k \mathbf{p}_k}<br>$$</p>
<p>利用Sherman-Morrison公式两次,对上式求逆,即可得到一种新的$\mathbf{V}_k$更新公式。最终可以得到BFGS算法如下:</p>
<blockquote>
<ol>
<li>初始化选择$\mathbf{V}_0$为一个对称正定矩阵,随机选择初始点$\mathbf{x}_0$并计算梯度$\mathbf{g}_0$,$k = 0$;</li>
<li>设置搜索方向为$\mathbf{d}_k = -\mathbf{V}_k \mathbf{g}_k$;</li>
<li>通过line search搜索最优的步长$\alpha$;</li>
<li>得到$\mathbf{x}_{k+1}$,计算当前梯度和$\mathbf{p}_k$、$\mathbf{q}_k$;</li>
<li>更新$\mathbf{V}_{k+1} = \mathbf{V}_k + (1 + \frac{\mathbf{q}_k^T \mathbf{V}_k \mathbf{q}_k}{\mathbf{p}_k^T \mathbf{q}_k})\frac{\mathbf{p}_k \mathbf{p}_k^T}{\mathbf{p}_k^T \mathbf{q}_k} - \frac{\mathbf{p}_k \mathbf{q}_k^T \mathbf{V}_k + \mathbf{V}_k \mathbf{q}_k \mathbf{p}_k^T}{\mathbf{p}_k^T \mathbf{q}_k}$;</li>
<li>设置$k = k + 1$,跳到步骤2。</li>
</ol>
</blockquote>
<p>BFGS算法的复杂度几乎与DFP相似,但是在实际使用中,BFGS比DFP的运行性能要好。同时,BFGS和DFP的下降方向都满足“共轭”梯度的性质(参见共轭梯度下降的推导)。BGFS的应用另一个拓展版本是L-BFGS,主要用于节省大规模计算时的内存开销。由于篇幅限制,此处不再展开。</p>
<h2 id="参考文献"><a href="#参考文献" class="headerlink" title="参考文献"></a>参考文献</h2><ol>
<li>Conjugate Gradient Method. <a href="http://web.cs.iastate.edu/~cs577/handouts/conjugate-gradient.pdf" target="_blank" rel="external">http://web.cs.iastate.edu/~cs577/handouts/conjugate-gradient.pdf</a>.</li>
<li>Overview of conjugate gradient method. <a href="https://www.youtube.com/watch?v=eAYohMUpPMA" target="_blank" rel="external">https://www.youtube.com/watch?v=eAYohMUpPMA</a>.</li>
</ol>
]]></content>
<categories>
<category> 研究 </category>
</categories>
<tags>
<tag> 算法 </tag>
</tags>
</entry>
<entry>
<title><![CDATA[算法-字符串模糊匹配-Google kickstart2017 Round A - Problem B]]></title>
<url>http://vectorliu.com/2017/03/06/algorithm-google-kickstart2017-roundA-problemB/</url>
<content type="html"><![CDATA[<h2 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h2><p>给定两个字符串,判断两个字符串是否匹配。字符串中出现的“*”可以匹配0-4个任意字符。比如如下输入样例:<br><a id="more"></a> </p>
<blockquote>
<p>3<br>****<br>It<br>Shakes*e<br>S*speare<br>Shakes*e<br>*peare</p>
</blockquote>
<p>对应的输出为:</p>
<blockquote>
<p>Case #1: TRUE<br>Case #2: TRUE<br>Case #3: FALSE</p>
</blockquote>
<h2 id="可能解法"><a href="#可能解法" class="headerlink" title="可能解法"></a>可能解法</h2><p>解决思路如下:</p>
<ol>
<li>将原始字符串进行扩展,一个“*”替换成“****”;</li>
<li>建立二维数组match[i][j],表示第一个字符串的[0,i]子串与第二个字符串的[0,j]是否匹配,由于*的存在,需要注意match数组存放的是;</li>
<li>动态规划求解,数组match的最后一个元素表示了是否匹配。动态规划的更新需要考虑一下两点:<ul>
<li>*可以匹配任何字符,但同时也可以不存在;</li>
<li>初值设置应该考虑特殊输入,比如空的字符串。</li>
</ul>
</li>
</ol>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div></pre></td><td class="code"><pre><div class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><iostream></span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><string></span></span></div><div class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></div><div class="line">{</div><div class="line"> <span class="keyword">int</span> T;</div><div class="line"> <span class="built_in">cin</span> >> T;</div><div class="line"></div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> Case = <span class="number">1</span>; Case <= T; Case++) {</div><div class="line"> <span class="built_in">string</span> first;</div><div class="line"> <span class="built_in">string</span> second;</div><div class="line"> <span class="built_in">cin</span> >> first;</div><div class="line"> <span class="built_in">cin</span> >> second;</div><div class="line"> <span class="built_in">string</span> firstc = <span class="string">"#"</span>;</div><div class="line"> <span class="built_in">string</span> secondc = <span class="string">"#"</span>;</div><div class="line"></div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>;i < first.size();i++){</div><div class="line"> <span class="keyword">if</span> (first[i] == <span class="string">'*'</span>)</div><div class="line"> firstc += <span class="string">"****"</span>;</div><div class="line"> <span class="keyword">else</span></div><div class="line"> firstc += first[i];</div><div class="line"> }</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>;i < second.size();i++){</div><div class="line"> <span class="keyword">if</span> (second[i] == <span class="string">'*'</span>)</div><div class="line"> secondc += <span class="string">"****"</span>;</div><div class="line"> <span class="keyword">else</span></div><div class="line"> secondc += second[i];</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">int</span> m = firstc.size();</div><div class="line"> <span class="keyword">int</span> n = secondc.size();</div><div class="line"> <span class="keyword">int</span> match[m][n];</div><div class="line"> match[<span class="number">0</span>][<span class="number">0</span>] = <span class="number">1</span>;</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>;i < m;i++){</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">0</span>; j < n; j++){</div><div class="line"> <span class="keyword">if</span> (i == <span class="number">0</span> && j == <span class="number">0</span>){</div><div class="line"> match[i][j] = <span class="number">1</span>;</div><div class="line"> }</div><div class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (i == <span class="number">0</span>){</div><div class="line"> match[i][j] = (secondc[j] == <span class="string">'*'</span>)?match[i][j<span class="number">-1</span>]:<span class="number">0</span>;</div><div class="line"> }</div><div class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (j == <span class="number">0</span>){</div><div class="line"> match[i][j] = (firstc[i] == <span class="string">'*'</span>)?match[i<span class="number">-1</span>][j]:<span class="number">0</span>;</div><div class="line"> }</div><div class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (i > <span class="number">0</span> && j > <span class="number">0</span>) {</div><div class="line"> match[i][j] =</div><div class="line"> match[i - <span class="number">1</span>][j - <span class="number">1</span>] && (firstc[i] == <span class="string">'*'</span> || secondc[j] == <span class="string">'*'</span> || firstc[i] == secondc[j]);</div><div class="line"> <span class="keyword">if</span> (firstc[i] == <span class="string">'*'</span>)</div><div class="line"> match[i][j] = match[i][j] || match[i - <span class="number">1</span>][j];</div><div class="line"> <span class="keyword">if</span> (secondc[j] == <span class="string">'*'</span>)</div><div class="line"> match[i][j] = match[i][j] || match[i][j - <span class="number">1</span>];</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }</div><div class="line"> <span class="keyword">if</span>(match[m<span class="number">-1</span>][n<span class="number">-1</span>])</div><div class="line"> <span class="built_in">cout</span> << <span class="string">"Case #"</span> << Case << <span class="string">": "</span> << <span class="string">"TRUE"</span> << <span class="built_in">endl</span>;</div><div class="line"> <span class="keyword">else</span></div><div class="line"> <span class="built_in">cout</span> << <span class="string">"Case #"</span> << Case << <span class="string">": "</span> << <span class="string">"FALSE"</span> << <span class="built_in">endl</span>;</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> <span class="number">0</span>;</div><div class="line">}</div></pre></td></tr></table></figure>
<h2 id="复杂度分析"><a href="#复杂度分析" class="headerlink" title="复杂度分析"></a>复杂度分析</h2><p>单次算法时间复杂度为$\mathcal{O}(n^2)$,空间复杂度也为$\mathcal{O}(n^2)$。</p>
]]></content>
<categories>
<category> 编程 </category>
</categories>
<tags>
<tag> 算法 </tag>
<tag> Google </tag>
</tags>
</entry>
<entry>
<title><![CDATA[算法-数方块-Google kickstart2017 Round A - Problem A]]></title>
<url>http://vectorliu.com/2017/03/05/algorithm-google-kickstart2017-roundA-problemA/</url>
<content type="html">< --></p>
<p>我们可以发现:</p>
<ul>
<li>边长为1的正方形有$(r - 1)(c - 1)$个;</li>
<li>边长为2的正方形有$(r - 2)(c - 2)$个,此外每个边长为2的正方形内部有一个斜的边长为$\sqrt{2}$正方形,因此总数为$2(r - 2)(c - 2)$;</li>
<li>边长为3的正方形有$(r - 3)(c - 3)$个,此外每个边长为3的正方形内部有一个斜的边长为$\sqrt{5}$正方形,因此总数为$3(r - 3)(c - 3)$;</li>
<li>边长为n的正方形及其内部的正方形共有$n(r - n)(c - n)$个。</li>
</ul>
<p>同时,最大的边长n满足:$n = \min \lbrace r - 1, c - 1 \rbrace$。据此已经可以通过循环求和得到结果,但是针对大样本时间会来不及。因此我们考虑自行化简如下:<br>$$<br>\begin{align}\\<br>&\sum\limits_{i=1}^{n}{i(r - i)(c - i)}\\<br>&= rc \cdot \sum\limits_{i=1}^{n}{i} - (r + c) \cdot \sum\limits_{i=1}^{n}{i^2} + \sum\limits_{i=1}^{n}{i^3}\\<br>&= \frac{n(n+1)}{2} \cdot rc - \frac{n(n+1)(2n+1)}{6} \cdot (r+c) + \frac{n^2(n+1)^2}{4}\\<br>\end{align}<br>$$<br>从而可以很方便的通过一次计算得到结果。最后,为了避免大数运算,需要在计算的过程中进行取模。要注意的是,由于中间有减法存在,需要检查最后的结果是否合法。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div></pre></td><td class="code"><pre><div class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><iostream></span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><string></span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><cmath></span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span><span class="meta-string"><fstream></span></span></div><div class="line"></div><div class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">int</span> <span class="keyword">module</span> = <span class="number">1000000007</span>;</div><div class="line"> <span class="keyword">int</span> T;</div><div class="line"> <span class="built_in">cin</span> >> T;</div><div class="line"></div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> Case = <span class="number">1</span>; Case <= T; Case++) {</div><div class="line"> <span class="keyword">int</span> r, c;</div><div class="line"> <span class="built_in">cin</span> >> r >> c;</div><div class="line"></div><div class="line"> <span class="keyword">long</span> m = min(r - <span class="number">1</span>, c - <span class="number">1</span>);</div><div class="line"> <span class="keyword">long</span> sum = <span class="number">0</span>;</div><div class="line"> <span class="keyword">long</span> temp1 = r * c;</div><div class="line"> <span class="keyword">long</span> temp2 = r + c;</div><div class="line"> sum += ((m + <span class="number">1</span>)*m/<span class="number">2</span> * temp1)%<span class="keyword">module</span>;</div><div class="line"> sum += -((<span class="keyword">int</span>)(m + <span class="number">1</span>)*m*(<span class="number">2</span>*m + <span class="number">1</span>)/<span class="number">6</span> *temp2)%<span class="keyword">module</span>;</div><div class="line"> sum += ((m + <span class="number">1</span>)*(m + <span class="number">1</span>)*m*m/<span class="number">4</span>)%<span class="keyword">module</span>;</div><div class="line"> sum = sum%<span class="keyword">module</span>;</div><div class="line"> <span class="keyword">if</span>(sum < <span class="number">0</span>){</div><div class="line"> sum += <span class="keyword">module</span>;</div><div class="line"> }</div><div class="line"> <span class="built_in">cout</span> << <span class="string">"Case #"</span> << Case << <span class="string">": "</span> << sum << <span class="built_in">endl</span>;</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> <span class="number">0</span>;</div><div class="line">}</div><div class="line">}</div></pre></td></tr></table></figure>
<h2 id="复杂度分析"><a href="#复杂度分析" class="headerlink" title="复杂度分析"></a>复杂度分析</h2><p>算法单次时间复杂度为$\mathcal{O}(1)$,空间复杂度也为$\mathcal{O}(1)$。</p>
]]></content>
<categories>
<category> 编程 </category>
</categories>
<tags>
<tag> 算法 </tag>
<tag> Google </tag>
</tags>
</entry>
<entry>
<title><![CDATA[算法—分块最大值之差]]></title>
<url>http://vectorliu.com/2017/03/05/algorithm-maximum-absolute-difference/</url>
<content type="html"><![CDATA[<h2 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h2><p>给定一维数组arr,其下标范围为$[0, n-1]$,将数组分为两个部分$[0, k]$和$[k+1, n-1]$,两部分都非空。求前后两部分最大值的差的绝对值的最大值。<br><a id="more"></a></p>
<h2 id="可能解法(python版)"><a href="#可能解法(python版)" class="headerlink" title="可能解法(python版)"></a>可能解法(python版)</h2><p>算法思想:首先,无论怎么分割,数组的全局最大值必然也是其中一部分的最大值。从数组头部开始看:</p>
<ul>
<li>如果$arr[0] \lt arr[1]$,则为保持左边的最大值最小,数组必须从从第一个元素后分段;</li>
<li>如果$arr[0] \ge arr[1]$,则新加入的$arr[1]$对左边的最大值无影响,直到再次满足上一个条件。<br>从尾部开始也可以得到类似的结论。因此,总结最大值之差的最大值满足如下表达式:<br>$$\max\lbrace arr \rbrace - \min \lbrace arr[0], arr[n - 1] \rbrace.$$</li>
</ul>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">maxDiff</span><span class="params">(arr)</span>:</span></div><div class="line"> n = len(arr)</div><div class="line"> <span class="keyword">if</span> len(arr) < <span class="number">2</span>:</div><div class="line"> <span class="keyword">return</span> <span class="number">-1</span></div><div class="line"> maxVal = arr[<span class="number">0</span>]</div><div class="line"> <span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">1</span>, len(arr)):</div><div class="line"> maxVal = arr[i] <span class="keyword">if</span> maxVal < arr[i] <span class="keyword">else</span> maxVal</div><div class="line"> <span class="keyword">return</span> maxVal - min(arr[<span class="number">0</span>], arr[n - <span class="number">1</span>])</div></pre></td></tr></table></figure>
<h2 id="复杂度分析"><a href="#复杂度分析" class="headerlink" title="复杂度分析"></a>复杂度分析</h2><p>算法时间复杂度为$\mathcal{O}(n)$,空间复杂度也为$\mathcal{O}(N)$。</p>
]]></content>
<categories>
<category> 编程 </category>
</categories>
<tags>
<tag> 算法 </tag>
</tags>
</entry>
<entry>
<title><![CDATA[算法-四等分数组-阿里2017年研发工程师JAVA(实习生)编程笔试]]></title>
<url>http://vectorliu.com/2017/03/02/algorithm-four-equal-partition/</url>
<content type="html"><![CDATA[<h2 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h2><p>给定一维数组arr,其元素都为正数,将其分为4个组,4个组的和分别相等,并且不包含分割位置的元素。判断给定数组是否符合该条件。<br><a id="more"></a> </p>
<h2 id="可能解法(python版)"><a href="#可能解法(python版)" class="headerlink" title="可能解法(python版)"></a>可能解法(python版)</h2><p>算法思想:将数组分为4个部分,共存在3个分界点。初始化3个分界点的合理位置,使得每一段都非空,同时初始化4个部分的和。从左边和右边开始扫描调整分界点位置,直到第1部分和第4部分相等。算法接着调整第2部分和第3部分,使得它们的部分和也相等。至此,可以比较第1段和第2段的和,如果满足第1段大于第2段,则不再有调整的可能,否则接着调整。算法利用了两个重要特征:</p>
<ul>
<li>数组中所有元素都是正数,因此加上一个数不会变小;</li>
<li>第1段和第4段的和都是从小往大递增的。</li>
</ul>
<figure class="highlight python"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">def</span> <span class="title">fourPartition</span><span class="params">(arr)</span>:</span></div><div class="line"> first, second, third = <span class="number">1</span>, len(arr)/<span class="number">2</span>, len(arr) - <span class="number">2</span></div><div class="line"> sum1 = sum2 = sum3 = sum4 = <span class="number">0</span></div><div class="line"> <span class="comment"># requires only one sweep</span></div><div class="line"> sum1 += sum(arr[<span class="number">0</span>:first])</div><div class="line"> sum2 += sum(arr[(first + <span class="number">1</span>):second])</div><div class="line"> sum3 += sum(arr[(second + <span class="number">1</span>):third])</div><div class="line"> sum4 += sum(arr[third + <span class="number">1</span>:])</div><div class="line"> <span class="keyword">if</span> sum1 * sum2 * sum3 * sum4 == <span class="number">0</span>:</div><div class="line"> <span class="keyword">return</span> <span class="keyword">False</span></div><div class="line"></div><div class="line"> <span class="keyword">while</span>(first < second - <span class="number">1</span>) <span class="keyword">and</span> (second < third - <span class="number">1</span>):</div><div class="line"> <span class="comment">#sum1 and sum4, from small to large, until equal</span></div><div class="line"> <span class="keyword">if</span> sum1 < sum4:</div><div class="line"> sum1 += arr[first]</div><div class="line"> sum2 -= arr[first + <span class="number">1</span>]</div><div class="line"> first += <span class="number">1</span></div><div class="line"> <span class="keyword">elif</span> sum1 > sum4:</div><div class="line"> sum4 += arr[third]</div><div class="line"> sum3 -= arr[third - <span class="number">1</span>]</div><div class="line"> third -= <span class="number">1</span></div><div class="line"> <span class="comment">#sum1 == sum4</span></div><div class="line"> <span class="keyword">else</span>:</div><div class="line"> <span class="keyword">if</span> sum2 < sum3:</div><div class="line"> sum2 += arr[second]</div><div class="line"> sum3 -= arr[second + <span class="number">1</span>]</div><div class="line"> second += <span class="number">1</span></div><div class="line"> <span class="keyword">elif</span> sum2 > sum3:</div><div class="line"> sum2 -= arr[second - <span class="number">1</span>]</div><div class="line"> sum3 += arr[second]</div><div class="line"> second -= <span class="number">1</span></div><div class="line"> <span class="comment">#sum2 == sum3</span></div><div class="line"> <span class="keyword">else</span>:</div><div class="line"> <span class="keyword">if</span> sum1 < sum2:</div><div class="line"> sum1 += arr[first]</div><div class="line"> sum2 -= arr[first + <span class="number">1</span>]</div><div class="line"> first += <span class="number">1</span></div><div class="line"> <span class="keyword">elif</span> sum1 > sum2:</div><div class="line"> <span class="keyword">return</span> <span class="keyword">False</span></div><div class="line"> <span class="comment">#sum1 == sum2</span></div><div class="line"> <span class="keyword">else</span>:</div><div class="line"> <span class="keyword">return</span> <span class="keyword">True</span></div><div class="line"></div><div class="line"> <span class="keyword">return</span> <span class="keyword">False</span></div></pre></td></tr></table></figure>
<h2 id="复杂度分析"><a href="#复杂度分析" class="headerlink" title="复杂度分析"></a>复杂度分析</h2><p>算法时间复杂度为$\mathcal{O}(n)$,空间复杂度也为$\mathcal{O}(N)$。</p>
]]></content>
<categories>
<category> 编程 </category>
</categories>
<tags>
<tag> 算法 </tag>
</tags>
</entry>
<entry>
<title><![CDATA[Hello World]]></title>
<url>http://vectorliu.com/2017/03/02/hello-world/</url>
<content type="html"><![CDATA[<p>Welcome to <a href="https://hexo.io/" target="_blank" rel="external">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/" target="_blank" rel="external">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html" target="_blank" rel="external">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues" target="_blank" rel="external">GitHub</a>.<br><a id="more"></a> </p>
<h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$ hexo new <span class="string">"My New Post"</span></div></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/writing.html" target="_blank" rel="external">Writing</a></p>
<h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$ hexo server</div></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/server.html" target="_blank" rel="external">Server</a></p>
<h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$ hexo generate</div></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/generating.html" target="_blank" rel="external">Generating</a></p>
<h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">$ hexo deploy</div></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/deployment.html" target="_blank" rel="external">Deployment</a></p>
]]></content>
</entry>
</search>