-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsearch.xml
More file actions
270 lines (266 loc) · 41.4 KB
/
Copy pathsearch.xml
File metadata and controls
270 lines (266 loc) · 41.4 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
261
262
263
264
265
266
267
268
269
270
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>Hello World</title>
<url>/2024/08/23/hello-world/</url>
<content><![CDATA[<p>Welcome to <a href="https://hexo.io/">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/">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">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues">GitHub</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="code"><pre><span class="line">$ hexo new <span class="string">"My New Post"</span></span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/writing.html">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="code"><pre><span class="line">$ hexo server</span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/server.html">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="code"><pre><span class="line">$ hexo generate</span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/generating.html">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="code"><pre><span class="line">$ hexo deploy</span><br></pre></td></tr></table></figure>
<p>More info: <a href="https://hexo.io/docs/one-command-deployment.html">Deployment</a></p>
<h3 id="recommend-blog-for-reference"><a href="#recommend-blog-for-reference" class="headerlink" title="recommend blog for reference"></a>recommend blog for reference</h3><p><a href="https://blog.csdn.net/cat_bayi/article/details/128725230">Blog</a></p>
]]></content>
<categories>
<category>开始</category>
</categories>
</entry>
<entry>
<title>前缀和</title>
<url>/2025/03/17/algorithms/PrefixSum/</url>
<content><![CDATA[<h1 id="前缀和"><a href="#前缀和" class="headerlink" title="前缀和"></a>前缀和</h1><blockquote>
<p>前缀和可以简单理解为:数列的前n项的和,是一种重要的数据预处理方式,可以大大降低查询的时间复杂度 ——oi-wiki</p>
</blockquote>
<h2 id="01-一维前缀和"><a href="#01-一维前缀和" class="headerlink" title="01 一维前缀和"></a>01 一维前缀和</h2><h3 id="1-构建方式"><a href="#1-构建方式" class="headerlink" title="1. 构建方式"></a>1. 构建方式</h3><p>给定大小为n的一维数组A,要求出其前缀和数组preData</p>
<ul>
<li>为了避免后续利用前缀和数组求区间和时出现数组index溢出的问题,preData数组大小为n+1,初始化preData[i]为0</li>
<li>遍历数组A,preData[i+1]=preData[i]+A[i]<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="function">vector<<span class="type">int</span>> <span class="title">preData</span><span class="params">(n<span class="number">+1</span>,<span class="number">0</span>)</span></span>;</span><br><span class="line"><span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">0</span>;i<n;i++){</span><br><span class="line"> preData[i<span class="number">+1</span>]=preData[i]+A[i];</span><br><span class="line">} </span><br></pre></td></tr></table></figure></li>
</ul>
<h3 id="2-使用场景"><a href="#2-使用场景" class="headerlink" title="2. 使用场景"></a>2. 使用场景</h3><h4 id="1-最基础的:求区间和"><a href="#1-最基础的:求区间和" class="headerlink" title="1.最基础的:求区间和"></a>1.最基础的:求区间和</h4><p> <a href="https://kamacoder.com/problempage.php?pid=1070">https://kamacoder.com/problempage.php?pid=1070</a> </p>
<ul>
<li>参考实现:<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><vector></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><sstream></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><numeric></span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="type">int</span> n;</span><br><span class="line"> cin>>n;</span><br><span class="line"> vector<<span class="type">int</span>> nums;</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">0</span>;i<n;i++){</span><br><span class="line"> <span class="type">int</span> tmp;</span><br><span class="line"> cin>>tmp;</span><br><span class="line"> nums.<span class="built_in">push_back</span>(tmp);</span><br><span class="line"> }</span><br><span class="line"> string line;</span><br><span class="line"> <span class="function">vector<<span class="type">int</span>> <span class="title">vec</span><span class="params">(n<span class="number">+1</span>,<span class="number">0</span>)</span></span>;</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">1</span>;i<=n;i++){</span><br><span class="line"> vec[i]=nums[i<span class="number">-1</span>]+vec[i<span class="number">-1</span>];</span><br><span class="line"> }</span><br><span class="line"> cin.<span class="built_in">ignore</span>();</span><br><span class="line"> <span class="keyword">while</span>(<span class="built_in">getline</span>(cin,line)){</span><br><span class="line"> <span class="function">istringstream <span class="title">ss</span><span class="params">(line)</span></span>;</span><br><span class="line"> <span class="type">int</span> a,b;</span><br><span class="line"> <span class="keyword">while</span>(ss>>a>>b){</span><br><span class="line"> cout<<vec[b<span class="number">+1</span>]-vec[a]<<endl;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li>
</ul>
<h4 id="2-小美的区间删除(美团笔试)"><a href="#2-小美的区间删除(美团笔试)" class="headerlink" title="2. 小美的区间删除(美团笔试)"></a>2. 小美的区间删除(美团笔试)</h4><p> <a href="https://www.nowcoder.com/exam/test/86815695/detail?pid=55750560">https://www.nowcoder.com/exam/test/86815695/detail?pid=55750560</a></p>
<ol>
<li>解法:</li>
</ol>
<ul>
<li>要求剩余所有元素乘积末尾至少有k个0,即剩余元素要至少有k对(2,5)。 </li>
<li>即<strong>任意区间的(2,5)因子对数</strong>不能超过<strong>总(2,5)因子对数</strong>-<strong>k</strong>。 </li>
<li>结合前缀和求出prefix数组,prefix[i]代表第i个元素前的(2,5)因子对数<br><em>此方法由于遍历区间时采用双层循环,会超时,可以进行优化。有相关优化思路也可以联系我的邮箱~</em><figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">#include <iostream></span><br><span class="line">#include <vector></span><br><span class="line">using namespace std;</span><br><span class="line">int get_count(int x, int factor) {</span><br><span class="line"> int count = 0;</span><br><span class="line"> while (x % factor == 0) { // 只要能整除 factor 就继续</span><br><span class="line"> count++;</span><br><span class="line"> x /= factor;</span><br><span class="line"> }</span><br><span class="line"> return count;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">int main() {</span><br><span class="line"> int n,k;</span><br><span class="line"> cin>>n>>k;</span><br><span class="line"> vector<int> a;</span><br><span class="line"> for(int i=0;i<n;i++){</span><br><span class="line"> int tmp;</span><br><span class="line"> cin>>tmp;</span><br><span class="line"> a.push_back(tmp);</span><br><span class="line"> }</span><br><span class="line"> vector<int> prefix2(n+1,0);</span><br><span class="line"> vector<int> prefix5(n+1,0);//统计2,5,使用前缀和</span><br><span class="line"> for(int i=0;i<n;i++){</span><br><span class="line"> int count_2= get_count(a[i],2);</span><br><span class="line"> int count_5= get_count(a[i],5);</span><br><span class="line"> prefix2[i+1]=prefix2[i]+count_2;</span><br><span class="line"> prefix5[i+1]=prefix5[i]+count_5;</span><br><span class="line"> }</span><br><span class="line"> int result=0;</span><br><span class="line"> for(int i=0;i<n;i++){</span><br><span class="line"> for(int j=i;j<n;j++){</span><br><span class="line"> int left_pair_2 = prefix2[n] - (prefix2[j+1] - prefix2[i]);</span><br><span class="line"> int left_pair_5 = prefix5[n] - (prefix5[j+1] - prefix5[i]);</span><br><span class="line"> int left_pair = min(left_pair_2, left_pair_5);</span><br><span class="line"> if(left_pair>=k){</span><br><span class="line"> result++;</span><br><span class="line"> }else{</span><br><span class="line"> break;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> cout<<result;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li>
</ul>
<h4 id="3-开发商购买土地"><a href="#3-开发商购买土地" class="headerlink" title="3. 开发商购买土地"></a>3. 开发商购买土地</h4><p><a href="https://kamacoder.com/problempage.php?pid=1044">https://kamacoder.com/problempage.php?pid=1044</a></p>
<ol>
<li>题目分析:</li>
</ol>
<ul>
<li>要求横向(纵向)划分后,上下(左右)两个子区域差距最小的情况</li>
<li>其实也是一维前缀和的变体,只不过单位不是元素,而是一行(列)</li>
</ul>
<ol start="2">
<li>解法:</li>
</ol>
<ul>
<li>以行和列分别为单位,求出对应的行/列的前缀和</li>
<li>横向或纵向遍历,找到所有划分中差距最小的情况<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span><span class="string"><vector></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><numeric></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><climits></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="type">int</span> n,m;</span><br><span class="line"> cin>>n>>m;</span><br><span class="line"> vector<vector<<span class="type">int</span>>> <span class="built_in">city</span>(n,<span class="built_in">vector</span><<span class="type">int</span>>(m,<span class="number">0</span>));</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">0</span>;i<n;i++){</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> j=<span class="number">0</span>;j<m;j++){</span><br><span class="line"> <span class="type">int</span> tmp;</span><br><span class="line"> cin>>tmp;</span><br><span class="line"> city[i][j]=tmp;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="function">vector<<span class="type">int</span>> <span class="title">sum_row</span><span class="params">(n<span class="number">+1</span>,<span class="number">0</span>)</span></span>;<span class="comment">//记录行的前缀和</span></span><br><span class="line"> <span class="function">vector<<span class="type">int</span>> <span class="title">sum_col</span><span class="params">(m<span class="number">+1</span>,<span class="number">0</span>)</span></span>;<span class="comment">//记录列的前缀和</span></span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">1</span>;i<=n;i++){</span><br><span class="line"> <span class="type">int</span> sum=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> j=<span class="number">0</span>;j<m;j++){</span><br><span class="line"> sum=sum+city[i<span class="number">-1</span>][j];</span><br><span class="line"> }</span><br><span class="line"> sum_row[i]=sum_row[i<span class="number">-1</span>]+sum;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">1</span>;i<=m;i++){</span><br><span class="line"> <span class="type">int</span> sum=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> j=<span class="number">0</span>;j<n;j++){</span><br><span class="line"> sum=sum+city[j][i<span class="number">-1</span>];</span><br><span class="line"> }</span><br><span class="line"> sum_col[i]=sum+sum_col[i<span class="number">-1</span>];</span><br><span class="line"> }</span><br><span class="line"> <span class="type">int</span> min_gap=INT_MAX;</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">1</span>;i<n;i++){</span><br><span class="line"> <span class="type">int</span> a=sum_row[i];</span><br><span class="line"> <span class="type">int</span> b=sum_row[n]-sum_row[i];</span><br><span class="line"> <span class="type">int</span> gap=<span class="built_in">abs</span>(a-b);</span><br><span class="line"> min_gap=<span class="built_in">min</span>(min_gap,gap);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> j=<span class="number">1</span>;j<m;j++){</span><br><span class="line"> <span class="type">int</span> a=sum_col[j];</span><br><span class="line"> <span class="type">int</span> b=sum_col[m]-sum_col[j];</span><br><span class="line"> <span class="type">int</span> gap=<span class="built_in">abs</span>(a-b);</span><br><span class="line"> min_gap=<span class="built_in">min</span>(min_gap,gap);</span><br><span class="line"> }</span><br><span class="line"> cout<<min_gap;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li>
</ul>
<h2 id="02-二维前缀和"><a href="#02-二维前缀和" class="headerlink" title="02 二维前缀和"></a>02 二维前缀和</h2><h3 id="1-构建方式-1"><a href="#1-构建方式-1" class="headerlink" title="1. 构建方式"></a>1. 构建方式</h3><blockquote>
<p>常见的多维前缀和的求解方法有两种,这里主要介绍本人常用的一种:基于容斥原理</p>
</blockquote>
<ul>
<li>对于大小m<em>n的二维数组A,同样为了避免index的溢出,创建(m+1)</em>(n+1)的前缀和数组preData<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line">preData[i<span class="number">+1</span>][j<span class="number">+1</span>]=A[i][j]+preData[i][j<span class="number">+1</span>]+preData[i<span class="number">+1</span>][j]-preData[i][j]</span><br></pre></td></tr></table></figure></li>
</ul>
<h3 id="2-使用场景-1"><a href="#2-使用场景-1" class="headerlink" title="2. 使用场景"></a>2. 使用场景</h3><h4 id="1-小美的平衡矩阵"><a href="#1-小美的平衡矩阵" class="headerlink" title="1. 小美的平衡矩阵"></a>1. 小美的平衡矩阵</h4><p><a href="https://www.nowcoder.com/exam/test/86815695/detail?pid=55750560&pageSource=testHistory">https://www.nowcoder.com/exam/test/86815695/detail?pid=55750560&pageSource=testHistory</a></p>
<ol>
<li>解法:</li>
</ol>
<ul>
<li>要求有多少个i*i的完美矩阵区域,即对于任意大小的矩阵可以知道这个矩阵的sum</li>
<li>先求出二维前缀和,矩阵长度从1-n,起点从0开始,遍历所有的可能<figure class="highlight cpp"><table><tr><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><vector></span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="comment">//得到矩阵大小</span></span><br><span class="line"> <span class="type">int</span> n;</span><br><span class="line"> cin >> n;</span><br><span class="line"></span><br><span class="line"> vector<vector<<span class="type">int</span>>> <span class="built_in">nums</span>(n<span class="number">+1</span>,<span class="built_in">vector</span><<span class="type">int</span>>(n<span class="number">+1</span>,<span class="number">0</span>));</span><br><span class="line"> string str;</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">1</span>;i<=n;i++){</span><br><span class="line"> cin>>str;</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> j=<span class="number">1</span>;j<=n;j++){</span><br><span class="line"> <span class="keyword">if</span>(str[j<span class="number">-1</span>]==<span class="string">'1'</span>){</span><br><span class="line"> nums[i][j]=<span class="number">1</span>;</span><br><span class="line"> }<span class="keyword">else</span>{</span><br><span class="line"> nums[i][j]=<span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> vector<vector<<span class="type">int</span>>> <span class="built_in">pre_data</span>(n<span class="number">+1</span>,<span class="built_in">vector</span><<span class="type">int</span>>(n<span class="number">+1</span>,<span class="number">0</span>));</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">1</span>;i<=n;i++){</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> j=<span class="number">1</span>;j<=n;j++){</span><br><span class="line"> pre_data[i][j]=pre_data[i][j<span class="number">-1</span>]+pre_data[i<span class="number">-1</span>][j]-pre_data[i<span class="number">-1</span>][j<span class="number">-1</span>]+nums[i][j];</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> k=<span class="number">1</span>;k<=n;k++){</span><br><span class="line"> <span class="type">int</span> count=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">if</span>(k%<span class="number">2</span>==<span class="number">0</span>){</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">1</span>;i<=n-k<span class="number">+1</span>;i++){</span><br><span class="line"> <span class="keyword">for</span>(<span class="type">int</span> j=<span class="number">1</span>;j<=n-k<span class="number">+1</span>;j++){</span><br><span class="line"> <span class="type">int</span> sum=pre_data[i+k<span class="number">-1</span>][j+k<span class="number">-1</span>]-pre_data[i+k<span class="number">-1</span>][j<span class="number">-1</span>]-pre_data[i<span class="number">-1</span>][j+k<span class="number">-1</span>]+pre_data[i<span class="number">-1</span>][j<span class="number">-1</span>];</span><br><span class="line"> <span class="keyword">if</span>(sum*<span class="number">2</span>==k*k){</span><br><span class="line"> count++;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> cout<<count<<endl;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure></li>
</ul>
]]></content>
<categories>
<category>算法</category>
</categories>
<tags>
<tag>prefixSum</tag>
</tags>
</entry>
<entry>
<title>JPA</title>
<url>/2025/03/21/projects/JPA/</url>
<content><![CDATA[<h1 id="JPA"><a href="#JPA" class="headerlink" title="JPA"></a>JPA</h1><h2 id="01-CRUD操作的实现"><a href="#01-CRUD操作的实现" class="headerlink" title="01 CRUD操作的实现"></a>01 CRUD操作的实现</h2><h3 id="1-支持动态查询"><a href="#1-支持动态查询" class="headerlink" title="1.支持动态查询"></a>1.支持动态查询</h3><blockquote>
<p>在查询某个实体时,常常会出现给定条件不定的情况,需要构建动态查询语句。<br>Spring Data JPA可以通过JpaSpecificationExecutor接口查询。</p>
</blockquote>
<h4 id="Specification"><a href="#Specification" class="headerlink" title="Specification"></a>Specification</h4><ol>
<li>Specification是规约模式,常在DDD中使用。将业务规则封装成独立的逻辑单元,从而将隐式业务规则提炼为显示概念达到代码复用的目的。</li>
</ol>
<ul>
<li>可以用于业务规则的抽象</li>
<li>可以用于数据查询</li>
</ul>
<ol start="2">
<li>如何实现规约模式</li>
</ol>
<ul>
<li>每条规约实现四个方法<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">ISpecification</span><T> {</span><br><span class="line"> bool <span class="title function_">IsSatisfiedBy</span><span class="params">(T o)</span>;</span><br><span class="line"> ISpecification<T> <span class="title function_">And</span><span class="params">(ISpecification<T> specification)</span>;</span><br><span class="line"> ISpecification<T> <span class="title function_">Or</span><span class="params">(ISpecification<T> specification)</span>;</span><br><span class="line"> ISpecification<T> <span class="title function_">Not</span><span class="params">(ISpecification<T> specification)</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li>
<li>IsSatisfied用于实现业务规则,其余用于复合业务逻辑</li>
</ul>
<h4 id="JPA中动态查询的实现"><a href="#JPA中动态查询的实现" class="headerlink" title="JPA中动态查询的实现"></a>JPA中动态查询的实现</h4><ol>
<li>实现Specification类,定义相关的查询条件<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">StoreSpecification</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> Specification<Store> <span class="title function_">searchInStore</span><span class="params">(<span class="type">boolean</span> sortedBySales,String category,String name)</span>{</span><br><span class="line"> <span class="keyword">return</span> (Root<Store> root, CriteriaQuery<?> query, CriteriaBuilder builder)->{</span><br><span class="line"> List<Predicate> predicates=<span class="keyword">new</span> <span class="title class_">ArrayList</span><>();</span><br><span class="line"> <span class="keyword">if</span>(category!=<span class="literal">null</span>&&!category.trim().isEmpty()&&!category.equals(<span class="string">"ALL"</span>)){</span><br><span class="line"> predicates.add(builder.equal(root.get(<span class="string">"category"</span>), StoreEnum.valueOf(category)));</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span>(name!=<span class="literal">null</span>&&!name.trim().isEmpty()){</span><br><span class="line"> predicates.add(builder.like(root.get(<span class="string">"name"</span>),<span class="string">"%"</span>+name+<span class="string">"%"</span>));</span><br><span class="line"> }</span><br><span class="line"> query.where(predicates.toArray(<span class="keyword">new</span> <span class="title class_">Predicate</span>[<span class="number">0</span>]));</span><br><span class="line"> <span class="keyword">if</span>(sortedBySales){</span><br><span class="line"> query.orderBy(builder.desc(root.get(<span class="string">"sales"</span>)));</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> builder.and(predicates.toArray(<span class="keyword">new</span> <span class="title class_">Predicate</span>[<span class="number">0</span>]));</span><br><span class="line"> };</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure></li>
</ol>
<ul>
<li>Specification<Store>是JPA提供的接口,用于动态构建查询条件;常与JpaSpecificationExecutor一起使用</li>
<li>Root是查询的根对象,即实体类。</li>
<li>CriteriaQuery<?>是一个JPA查询对象,用于定义查询结构</li>
<li>Predicate表示查询条件</li>
</ul>
<ol start="2">
<li>使用动态的查询条件<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">Specification<Store> spec= StoreSpecification.searchInStore(sortedBySales,category,name);</span><br><span class="line">Page<Store> storeList=storeRepository.findAll(spec,PageRequest.of(pageNum-<span class="number">1</span>,size));</span><br></pre></td></tr></table></figure></li>
</ol>
<h2 id="02-分页机制"><a href="#02-分页机制" class="headerlink" title="02 分页机制"></a>02 分页机制</h2><h3 id="1-分页机制概念"><a href="#1-分页机制概念" class="headerlink" title="1. 分页机制概念"></a>1. 分页机制概念</h3><ol>
<li>分页机制包括</li>
</ol>
<ul>
<li>分页参数(页码、页的大小)</li>
<li>分页结果(数据列表,总记录数,总页数)</li>
</ul>
<ol start="2">
<li>JPA中的分页机制</li>
</ol>
<ul>
<li>Pageable接口,封装分页的参数:常用PageRequest类构建该对象</li>
<li>Page接口,封装分页查询结果</li>
<li>Sort,对分页结果排序</li>
</ul>
]]></content>
<categories>
<category>项目开发</category>
<category>JPA</category>
</categories>
</entry>
<entry>
<title>商城秒杀</title>
<url>/2025/03/21/projects/miaosha/</url>
<content><![CDATA[<h1 id="商城秒杀"><a href="#商城秒杀" class="headerlink" title="商城秒杀"></a>商城秒杀</h1><p>参考文章:<a href="https://zhuanlan.zhihu.com/p/602162593">https://zhuanlan.zhihu.com/p/602162593</a></p>
<h2 id="01-秒杀的需求"><a href="#01-秒杀的需求" class="headerlink" title="01.秒杀的需求"></a>01.秒杀的需求</h2><h3 id="一、关于ID"><a href="#一、关于ID" class="headerlink" title="一、关于ID"></a>一、关于ID</h3><ol>
<li>是否能像普通业务一样使用自增的Id?<br>答案是不能,主要原因有以下两个</li>
</ol>
<ul>
<li>自增的Id太有规律性,会向用户暴露信息:当前一段时间内没有其他顾客下单</li>
<li>秒杀时订单量庞大,可能达到几百万甚至更多,Mysql数据库是不可能在一张表中存放如此多的数据的。但是如果拆成多张表后还是用自增的Id,会导致订单出现重复的Id,这是不符合业务逻辑的。</li>
</ul>
<ol start="2">
<li>如何解决以上问题?<br>需要一个全局ID生成器(一种在分布式系统下用来生成全局唯一ID的工具),满足:</li>
</ol>
<ul>
<li>唯一性</li>
<li>高性能</li>
<li>高可用</li>
<li>递增性</li>
<li>安全性</li>
</ul>
<ol start="3">
<li>如何实现全局ID生成器?<br>(1)一<br>使用Redis的自增技术并与其他进行拼接:<br>符号位+时间戳+序列号</li>
</ol>
<ul>
<li>利用redis的increment:string RedisTemplate.opsForValue()<br>.increment(“icr:” + keyPrefix + “:” + date);一天生成一个key</li>
<li>timestamp+计数器<br>(2)<br>UUID:用于在分布式系统中生成唯一的标识。它是一个128位的数字,通常以32个十六进制数字的形式表示,并通过分组和连字符分隔,例如:123e4567-e89b-12d3-a456-426614174000 </li>
<li>版本1(基于时间):使用时间戳和设备的MAC地址生成。这种版本的UUID可以反映生成的时间顺序,但可能会暴露设备的MAC地址,存在一定的隐私问题。</li>
<li>版本2(基于DCE安全):与版本1类似,但加入了POSIX UID/GID信息,主要用于分布式计算环境(DCE)。</li>
<li>版本3(基于名称的MD5散列):通过将一个命名空间的UUID和一个名称进行MD5散列生成。它适用于需要根据特定名称生成唯一标识的场景。</li>
<li>版本4(随机生成):完全由随机数或伪随机数生成。这是最常用的版本,因为它简单且不依赖于外部信息。</li>
<li>版本5(基于名称的SHA-1散列):与版本3类似,但使用SHA-1散列算法。它比版本3更安全,因为SHA-1比MD5更难被破解。</li>
</ul>
<h3 id="超卖问题"><a href="#超卖问题" class="headerlink" title="超卖问题"></a>超卖问题</h3><p>为什么会产生超卖?</p>
<ul>
<li>两个及以上线程同时访问并对数据进行修改<br><img src="https://pic2.zhimg.com/v2-175e9ccc3ba3e21f7c75f6da0650f181_1440w.jpg"></li>
</ul>
<h4 id="1-如何解决超卖问题?(典型的多线程安全问题)"><a href="#1-如何解决超卖问题?(典型的多线程安全问题)" class="headerlink" title="1.如何解决超卖问题?(典型的多线程安全问题)"></a>1.如何解决超卖问题?(典型的多线程安全问题)</h4><p>加锁!</p>
<ol>
<li>锁:</li>
</ol>
<ul>
<li>悲观锁:认为线程安全问题一定会发生,在操作数据前一定会先获取锁,确保线程串行执行,如synchronized,lock。</li>
<li>乐观锁:认为线程安全问题不一定会发生,不加锁,只有在更新数据时才判断有没有其他线程对数据进行了修改。</li>
</ul>
<ol start="2">
<li>悲观锁:<br>(1)java中最常用的锁就是synchronized关键字,对方法或者代码块进行同步。但是可能导致线程阻塞影响性能、锁粒度过大。<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">public</span> Boolean <span class="title function_">deleteOrdersById</span><span class="params">(<span class="type">int</span> orderId)</span> {</span><br><span class="line"> <span class="keyword">synchronized</span> (<span class="built_in">this</span>) { <span class="comment">// 对整个方法加锁</span></span><br><span class="line"> <span class="type">Orders</span> <span class="variable">orders</span> <span class="operator">=</span> ordersRepository.findById(orderId);</span><br><span class="line"> <span class="type">Good</span> <span class="variable">good</span> <span class="operator">=</span> goodRepository.findById(orders.getGoodId());</span><br><span class="line"> good.setStorage(good.getStorage() + orders.getSoldNum());</span><br><span class="line"> goodRepository.save(good);</span><br><span class="line"> ordersRepository.deleteById(orderId);</span><br><span class="line"> orderReportRepository.deleteById(orderId);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure></li>
</ol>
<ul>
<li>可以直接在方法前加该关键字,整个方法都会同步。注意:对于非静态,创建不同的对象后即使方法前有synchronized关键字也无法同步,因为属于不同对象就创建了不同对象锁。</li>
<li>也可以只对代码块同步,减少粒度 </li>
<li><strong>实现原理</strong>:是基于JVM的内置锁,也被称为互斥锁。<a href="https://zhuanlan.zhihu.com/p/377423211">https://zhuanlan.zhihu.com/p/377423211</a><ul>
<li>Java中每个对象都有一个对象头,包含其元数据(哈希码、锁信息等)。</li>
<li>即MarkWord:存储哈希码、锁标记位等</li>
<li>ClassMetadataAddress,存储到对象类型数据的指针</li>
<li>ArrayLength: 数组长度</li>
<li>JVM通过进入和退出Monitor(管程)实现</li>
<li>1.6后优化,因为之前的涉及用户态与内核态的转换,加入无、偏向、轻量级、重量级<br><em>事实上,很多项目都不是单例模式,方法也不会定义成静态,所以直接用synchronized并没有用,可以采取把synchronized加到controller层,serviceImpl加上@Transactional注解</em><br>(2)Lock</li>
<li>Lock()</li>
<li>tryLock()</li>
<li>unLock()</li>
</ul>
</li>
</ul>
<ol start="4">
<li>乐观锁:<br>(1)添加版本号</li>
</ol>
<ul>
<li>每扣减一次更改一下版本号,每次扣减之前查询版本号,只有在扣减时的版本号与之前版本号相同时才扣减<br>(2)CAS法</li>
<li>CAS操作包含三个操作数,内存位置、预期原值、新值</li>
<li>传统做法:如果内存位置V等于预期原值,就将其更新为新值;否则不操作</li>
<li>优化后,判断内存位置是否为零</li>
</ul>
<h4 id="一人一单(一个用户只可以购买一单)"><a href="#一人一单(一个用户只可以购买一单)" class="headerlink" title="一人一单(一个用户只可以购买一单)"></a>一人一单(一个用户只可以购买一单)</h4><p>在扣除库存前需要先去查找数据库中是否已经有该用户的订单,再去决定是否扣除。但是,这里分成了两步,可能引发线程安全问题。</p>
<ul>
<li>一方面查询是否已经有订单</li>
<li>另一方面,订单可能还没写入:锁住用户<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">synchronized</span> (userId.toString().intern()) {</span><br><span class="line"> ......</span><br><span class="line"> createVoucherOrder(voucherId);</span><br><span class="line"> ......</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<strong>需要分布式锁</strong></li>
</ul>
<ol>
<li>基于Redis的分布式锁</li>
</ol>
<ul>
<li>获取锁(设置key)</li>
<li>释放锁(删除key),为key设置一个超时时间,每个线程只能释放自己的</li>
</ul>
]]></content>
<categories>
<category>项目开发</category>
</categories>
</entry>
<entry>
<title>JWT</title>
<url>/2025/03/21/projects/JWT/</url>
<content><![CDATA[<h1 id="JWT(JSON-Web令牌)"><a href="#JWT(JSON-Web令牌)" class="headerlink" title="JWT(JSON Web令牌)"></a>JWT(JSON Web令牌)</h1><p>参考:<a href="https://jwt.p2hp.com/introduction%EF%BC%8Chttps://blog.csdn.net/Top_L398/article/details/109361680">https://jwt.p2hp.com/introduction,https://blog.csdn.net/Top_L398/article/details/109361680</a></p>
<h2 id="01-什么是JWT?"><a href="#01-什么是JWT?" class="headerlink" title="01 什么是JWT?"></a>01 什么是JWT?</h2><h3 id="1-定义"><a href="#1-定义" class="headerlink" title="1.定义"></a>1.定义</h3><blockquote>
<p>JWT是一种开放标准,定义了一种紧凑且独立的方式,用于在各方之间以JSON对象的形式安全传输信息。此信息是可以验证和信任的,因为它经过了数字签名。JWT可以使用密钥(HMAC算法)或RSA或ECDA的公钥/私钥对进行签名。</p>
</blockquote>
<p>即通过JSON形式作为Web应用中的令牌,从而在各方之间安全地将信息作为JSON对象传输,传输过程中还可以完成数据加密、签名等 </p>
<h3 id="2-JWT结构"><a href="#2-JWT结构" class="headerlink" title="2. JWT结构"></a>2. JWT结构</h3><p>JWT由三部分组成,由点’.’分隔,形如xxxxx.yyyyy.zzzzz</p>
<ol>
<li>Header, 标头:包括令牌的类型和使用的签名算法(如RSA)<figure class="highlight json"><table><tr><td class="code"><pre><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"alg"</span><span class="punctuation">:</span> <span class="string">"HS256"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"typ"</span><span class="punctuation">:</span> <span class="string">"JWT"</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure></li>
<li>Payload, 有效荷载</li>
<li>Signature, 签名</li>
</ol>
<h2 id="02-JWT的使用场景"><a href="#02-JWT的使用场景" class="headerlink" title="02 JWT的使用场景"></a>02 JWT的使用场景</h2><h3 id="1-授权"><a href="#1-授权" class="headerlink" title="1. 授权"></a>1. 授权</h3><ol>
<li>授权是JWT使用最广泛的场景,用户登录后的每个请求都将包含JWT,允许用户访问该令牌允许的路由、服务和资源。单点登录就使用了JWT,它开销很小并且可以轻松地跨域使用。</li>
</ol>
<ul>
<li>补充:单点登录(SSO)是一种用户身份验证过程,允许用户在多个应用程序或服务之间无缝访问,无需为每个应用单独登录。 比如:一个公司采取单点登录系统,提供了邮件系统、项目平台、文档平台,实现<br>单点登录后,先访问公司的单点登录门户网站注册并登录,之后当你希望登录邮件系统时,会被重定向到单点登录门户,会自动识别身份无需重复登录。</li>
</ul>
<h3 id="2-信息交换"><a href="#2-信息交换" class="headerlink" title="2. 信息交换"></a>2. 信息交换</h3><ol>
<li>JWT是在各方之间安全传输信息的好方法。因为 JWT 可以签名——例如,使用公钥/私钥对——你可以确定发送者是他们所说的人。此外,由于签名是使用标头和有效负载计算的,因此您还可以验证内容是否未被篡改.</li>
</ol>
]]></content>
<categories>
<category>项目开发</category>
</categories>
</entry>
<entry>
<title>文献综述</title>
<url>/2025/03/17/my-study/llm-copyright-and-compilence/review/</url>
<content><![CDATA[<h1 id="生成式AI安全合规"><a href="#生成式AI安全合规" class="headerlink" title="生成式AI安全合规"></a>生成式AI安全合规</h1><blockquote>
<p>针对生成式AI安全合规这一主题,本文主要探讨的问题是“⽣成内容版权与许可证合规的评测⽅法有哪些”</p>
</blockquote>
]]></content>
<categories>
<category>生成式AI安全合规</category>
<category>系统文献综述</category>
</categories>
</entry>
</search>