Skip to content

Commit 1d5afbb

Browse files
committed
📚sort
1 parent 29ccfcc commit 1d5afbb

File tree

10 files changed

+261
-79
lines changed

10 files changed

+261
-79
lines changed

docs/.DS_Store

0 Bytes
Binary file not shown.

docs/.obsidian/workspace.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@
213213
},
214214
"active": "e24a131a4a8c13f9",
215215
"lastOpenFiles": [
216+
"interview/Ability-FAQ~.md",
216217
"data-structure-algorithms/algorithm/BFS.md",
217218
"data-structure-algorithms/algorithm/Untitled.md",
218219
"interview/Algorithm.md",
@@ -239,7 +240,6 @@
239240
"Untitled.md",
240241
"2024-08-05.md",
241242
"java/JVM/GC.md",
242-
"interview/RPC-FAQ~.md",
243243
"data-structure-algorithms/algorithm",
244244
"data-structure-algorithms/未命名文件夹"
245245
]

docs/data-structure-algorithms/algorithm/Double-Pointer.md

Lines changed: 134 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -69,19 +69,6 @@ public void reverseString(char[] s) {
6969
}
7070
```
7171
72-
简化一下
73-
74-
```java
75-
public void reverseString(char[] s) {
76-
int n = s.length;
77-
for (int left = 0, right = n - 1; left < right; ++left, --right) {
78-
char tmp = s[left];
79-
s[left] = s[right];
80-
s[right] = tmp;
81-
}
82-
}
83-
```
84-
8572

8673

8774
### [两数之和 II - 输入有序数组](https://leetcode.cn/problems/two-sum-ii-input-array-is-sorted/)
@@ -170,7 +157,7 @@ public List<List<Integer>> threeSum(int[] nums) {
170157
//不要用成 if 判断,只跳过 1 条,还会有重复的,且需要再加上 l<r,以防死循环
171158
while (l < r && nums[l] == nums[l + 1]) l++;
172159
while (l < r && nums[r] == nums[r - 1]) r--;
173-
//移动指针
160+
//移动指针, 必须在去重后再移动
174161
l++;
175162
r--;
176163
}
@@ -370,6 +357,8 @@ public boolean hasCycle(ListNode head) {
370357
371358
372359
360+
361+
373362
### [链表的中间结点](https://leetcode.cn/problems/middle-of-the-linked-list/)
374363
375364
> 给定一个头结点为 `head` 的非空单链表,返回链表的中间结点。
@@ -629,20 +618,6 @@ public static double getMaxAverage(int[] nums, int k) {
629618
630619

631620

632-
#### [字符串的排列(567)](https://leetcode.cn/problems/permutation-in-string/description/)
633-
634-
> 给你两个字符串 `s1``s2` ,写一个函数来判断 `s2` 是否包含 `s1` 的排列。如果是,返回 `true` ;否则,返回 `false`
635-
>
636-
> 换句话说,`s1` 的排列之一是 `s2`**子串**
637-
>
638-
> ```
639-
> 输入:s1 = "ab" s2 = "eidbaooo"
640-
> 输出:true
641-
> 解释:s2 包含 s1 的排列之一 ("ba").
642-
> ```
643-
644-
645-
646621
### 3.2 不定长度的滑动窗口
647622

648623
#### [无重复字符的最长子串(3)](https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/)
@@ -720,7 +695,138 @@ int lengthOfLongestSubstring(String s) {
720695
> 输出:"BANC"
721696
> ```
722697
698+
思路:
723699
700+
1. 我们在字符串 `S` 中使用双指针中的左右指针技巧,初始化 `left = right = 0`,把索引**左闭右开**区间 `[left, right)` 称为一个「窗口」。
701+
702+
> [!IMPORTANT]
703+
>
704+
> 为什么要「左闭右开」区间
705+
>
706+
> **理论上你可以设计两端都开或者两端都闭的区间,但设计为左闭右开区间是最方便处理的**。
707+
>
708+
> 因为这样初始化 `left = right = 0` 时区间 `[0, 0)` 中没有元素,但只要让 `right` 向右移动(扩大)一位,区间 `[0, 1)` 就包含一个元素 `0` 了。
709+
>
710+
> 如果你设置为两端都开的区间,那么让 `right` 向右移动一位后开区间 `(0, 1)` 仍然没有元素;如果你设置为两端都闭的区间,那么初始区间 `[0, 0]` 就包含了一个元素。这两种情况都会给边界处理带来不必要的麻烦。
711+
712+
2. 我们先不断地增加 `right` 指针扩大窗口 `[left, right)`,直到窗口中的字符串符合要求(包含了 `T` 中的所有字符)。
713+
714+
3. 此时,我们停止增加 `right`,转而不断增加 `left` 指针缩小窗口 `[left, right)`,直到窗口中的字符串不再符合要求(不包含 `T` 中的所有字符了)。同时,每次增加 `left`,我们都要更新一轮结果。
715+
716+
4. 重复第 2 和第 3 步,直到 `right` 到达字符串 `S` 的尽头。
717+
718+
```java
719+
public String minWindow(String s, String t) {
720+
// 两个map,window 代表字符字符出现的次数,need 记录所需字符出现次数
721+
HashMap<Character, Integer> window = new HashMap<>();
722+
HashMap<Character, Integer> need = new HashMap<>();
723+
724+
for (int i = 0; i < t.length(); i++) {
725+
char c = t.charAt(i);
726+
//算出每个字符的数量,有可能有重复的
727+
need.put(c, need.getOrDefault(c, 0) + 1);
728+
}
729+
730+
//左开右闭的区间,然后创建移动窗口
731+
int left = 0, right = 0;
732+
// 窗口中满足need条件的字符个数, valid == need.size 说明窗口满足条件
733+
int valid = 0;
734+
//记录最小覆盖子串的开始索引和长度
735+
int start = 0, len = Integer.MAX_VALUE;
736+
while (right < s.length()) {
737+
// c 代表将移入窗口的字符
738+
char c = s.charAt(right);
739+
//扩大窗口
740+
right++;
741+
742+
if (need.containsKey(c)) {
743+
window.put(c, window.getOrDefault(c, 0) + 1);
744+
if (window.get(c).equals(need.get(c))) {
745+
valid++;
746+
}
747+
}
748+
//判断左窗口是否需要收缩
749+
while (valid == need.size()) {
750+
if (right - left < len) {
751+
start = left;
752+
len = right - left;
753+
}
754+
//d 是将移除窗口的字符
755+
char d = s.charAt(left);
756+
left++; //缩小窗口
757+
758+
//更新窗口
759+
if (need.containsKey(d)) {
760+
if (window.get(d).equals(need.get(d))) {
761+
valid--;
762+
window.put(d, window.get(d) - 1);
763+
}
764+
}
765+
}
766+
}
767+
//返回最小覆盖子串
768+
return len == Integer.MAX_VALUE ? "" : s.substring(start, start + len);
769+
}
770+
```
771+
772+
773+
774+
#### [字符串的排列(567)](https://leetcode.cn/problems/permutation-in-string/description/)
775+
776+
> 给你两个字符串 `s1``s2` ,写一个函数来判断 `s2` 是否包含 `s1` 的排列。如果是,返回 `true` ;否则,返回 `false`
777+
>
778+
> 换句话说,`s1` 的排列之一是 `s2`**子串**
779+
>
780+
> ```
781+
> 输入:s1 = "ab" s2 = "eidbaooo"
782+
> 输出:true
783+
> 解释:s2 包含 s1 的排列之一 ("ba").
784+
> ```
785+
786+
思路:和上一题基本一致,只是 移动 `left` 缩小窗口的时机是窗口大小大于 `t.length()` 时,当发现 `valid == need.size()` 时,就说明窗口中就是一个合法的排列
787+
788+
```java
789+
class Solution {
790+
// 判断 s 中是否存在 t 的排列
791+
public boolean checkInclusion(String t, String s) {
792+
Map<Character, Integer> need = new HashMap<>();
793+
Map<Character, Integer> window = new HashMap<>();
794+
for (char c : t.toCharArray()) {
795+
need.put(c, need.getOrDefault(c, 0) + 1);
796+
}
797+
798+
int left = 0, right = 0;
799+
int valid = 0;
800+
while (right < s.length()) {
801+
char c = s.charAt(right);
802+
right++;
803+
// 进行窗口内数据的一系列更新
804+
if (need.containsKey(c)) {
805+
window.put(c, window.getOrDefault(c, 0) + 1);
806+
if (window.get(c).intValue() == need.get(c).intValue())
807+
valid++;
808+
}
809+
810+
// 判断左侧窗口是否要收缩
811+
while (right - left >= t.length()) {
812+
// 在这里判断是否找到了合法的子串
813+
if (valid == need.size())
814+
return true;
815+
char d = s.charAt(left);
816+
left++;
817+
// 进行窗口内数据的一系列更新
818+
if (need.containsKey(d)) {
819+
if (window.get(d).intValue() == need.get(d).intValue())
820+
valid--;
821+
window.put(d, window.get(d) - 1);
822+
}
823+
}
824+
}
825+
// 未找到符合条件的子串
826+
return false;
827+
}
828+
}
829+
```
724830
725831

726832

@@ -744,10 +850,6 @@ int lengthOfLongestSubstring(String s) {
744850
745851
思路:
746852
747-
-
748-
749-
750-
751853
```java
752854
public int characterReplacement(String s, int k) {
753855
int len = s.length();

docs/data-structure-algorithms/algorithm/Sort.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,10 @@ public class BucketSort {
568568
- 什么时候最快:当输入的数据可以均匀的分配到每一个桶中。
569569
- 什么时候最慢:当输入的数据被分配到了同一个桶中。
570570

571+
> 思路一定要理解了,不背题哈,比如有些直接问你
572+
>
573+
> 已知一组记录的排序码为(46,79,56,38,40,80, 95,24),写出对其进行快速排序的第一趟的划分结果
574+
571575

572576

573577
## 基数排序

docs/design-pattern/Template-Pattern.md

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,19 @@
1616

1717
假设我们是一家饮品店的师傅,起码需要以下两个手艺
1818

19-
![](https://tva1.sinaimg.cn/large/007S8ZIlly1gigzsl1cnpj32gj0sk4ck.jpg)
19+
![img](https://static001.geekbang.org/infoq/19/196f4c041c71d63442c2c688051c893a.jpeg)
2020

2121
真简单哈,这么看,步骤大同小异,我的第一反应就是写个业务接口,不同的饮品实现其中的方法就行,像这样
2222

23-
![](https://tva1.sinaimg.cn/large/007S8ZIlly1gih087fykdj31pk0u0nbj.jpg)
23+
![img](https://static001.geekbang.org/infoq/a2/a226b8a9219cd7a29af2f3b626cd5fcb.jpeg)
2424

2525

2626

2727
画完类图,猛地发现,第一步和第三步没什么差别,而且做饮品是个流程式的工作,我希望使用时,直接调用一个方法,就去执行对应的制作步骤。
2828

2929
灵机一动,不用接口了,用一个**抽象父类**,把步骤方法放在一个大的流程方法 `makingDrinks()` 中,且第一步和第三步,完全一样,没必要在子类实现,改进如下
3030

31-
![](https://tva1.sinaimg.cn/large/007S8ZIlly1giidk5vt5cj31pf0u0nal.jpg)
31+
![img](https://static001.geekbang.org/infoq/21/2146409c43149828b8a12949daf5b0a4.jpeg)
3232

3333
再看下我们的设计,感觉还不错,现在用同一个 `makingDrinks()` 方法来处理咖啡和茶的制作,而且我们不希望子类覆盖这个方法,所以可以申明为 final,不同的制作步骤,我们希望子类来提供,必须在父类申明为抽象方法,而第一步和第三步我们不希望子类重写,所以我们声明为非抽象方法
3434

@@ -117,7 +117,7 @@ public static void main(String[] args) {
117117

118118
模板方法模式是所有模式中最为常见的几个模式之一,是**基于继承**的代码复用的基本技术,我们再看下类图
119119

120-
![](https://tva1.sinaimg.cn/large/007S8ZIlly1gih2dmwutxj31ug0u0h0i.jpg)
120+
![img](https://static001.geekbang.org/infoq/b1/b114ec408fb0231529d8748618df9ed7.jpeg)
121121

122122
模板方法模式就是用来创建一个算法的模板,这个模板就是方法,该方法将算法定义成一组步骤,其中的任意步骤都可能是抽象的,由子类负责实现。这样可以**确保算法的结构保持不变,同时由子类提供部分实现**
123123

@@ -207,7 +207,7 @@ public class Coffee extends Drinks {
207207

208208
接着再去测试下代码,看看结果吧。
209209

210-
![](https://tva1.sinaimg.cn/large/007S8ZIlly1gih3og312yj315y07uta9.jpg)
210+
![img](https://static001.geekbang.org/infoq/e6/e608360ad552adc44dab00293fddd671.jpeg)
211211

212212

213213

@@ -252,7 +252,7 @@ public static void main(String[] args) {
252252
}
253253
```
254254

255-
![](https://tva1.sinaimg.cn/large/007S8ZIlly1giha6rya5nj319006adhb.jpg)
255+
![img](https://static001.geekbang.org/infoq/92/9241c28ee542321b3e6f4e2a2fbf805a.jpeg)
256256

257257
你可能会说,这个看着不像我们常规的模板方法,是的。我们看下比较器实现的步骤
258258

@@ -329,7 +329,7 @@ public abstract class AbstractRefreshableWebApplicationContext extends …… {
329329

330330
看下大概的类图:
331331

332-
![](https://tva1.sinaimg.cn/large/007S8ZIlly1giie97gicdj31c20u0hdt.jpg)
332+
![img](https://static001.geekbang.org/infoq/13/1360f5528a2e86e5b0d0bf3a97b3c04b.jpeg)
333333

334334

335335

@@ -350,5 +350,3 @@ public abstract class AbstractRefreshableWebApplicationContext extends …… {
350350
《Head First 设计模式》、《研磨设计模式》
351351

352352
https://sourcemaking.com/design_patterns/template_method
353-
354-
![](https://cdn.jsdelivr.net/gh/Jstarfish/picBed/img/20200907141047.png)

docs/interview/.DS_Store

2 KB
Binary file not shown.

docs/interview/Ability-FAQ.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,3 +154,6 @@ ls –la input_file_name
154154
- **个人经验**: 可以提到如何配置 Prometheus 采集日志指标、设置警报规则,以及如何利用 Grafana 创建可视化面板。
155155

156156
我们使用 ELK Stack 来集中管理和分析日志数据。通过 Logstash 我们收集来自不同服务的日志,并将其存储在 Elasticsearch 中,然后使用 Kibana 创建了多个仪表盘来监控系统的健康状况和性能
157+
158+
159+

docs/interview/Design-Pattern-FAQ.md

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,7 @@ public class Singleton
5555
{
5656
}
5757

58-
public static Singleton getInstance()
59-
{
58+
public static Singleton getInstance(){
6059
if (singleton == null)
6160
singleton = new Singleton();
6261
return singleton;
@@ -71,12 +70,10 @@ public class Singleton
7170
{
7271
private static Singleton singleton;
7372

74-
private Singleton()
75-
{
73+
private Singleton(){
7674
}
7775

78-
public synchronized static Singleton getInstance()
79-
{
76+
public synchronized static Singleton getInstance(){
8077
if (singleton == null)
8178
singleton = new Singleton();
8279
return singleton;

0 commit comments

Comments
 (0)