Skip to content

Commit f104850

Browse files
committed
整理文件
1 parent c3aa5c5 commit f104850

File tree

65 files changed

+3185
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+3185
-0
lines changed
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# LeetCode 第 131 号问题:分割回文串
2+
3+
> 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一。
4+
>
5+
> 同步博客:https://www.algomooc.com
6+
7+
题目来源于 LeetCode 上第 131 号问题:分割回文串。题目难度为 Medium,目前通过率为 45.8% 。
8+
9+
### 题目描述
10+
11+
给定一个字符串 *s*,将 *s* 分割成一些子串,使每个子串都是回文串。
12+
13+
返回 *s* 所有可能的分割方案。
14+
15+
**示例:**
16+
17+
```yaml
18+
输入: "aab"
19+
输出:
20+
[
21+
["aa","b"],
22+
["a","a","b"]
23+
]
24+
```
25+
26+
###
27+
28+
### 题目解析
29+
30+
首先,对于一个字符串的分割,肯定需要将所有分割情况都遍历完毕才能判断是不是回文数。不能因为 **abba** 是回文串,就认为它的所有子串都是回文的。
31+
32+
既然需要将所有的分割方法都找出来,那么肯定需要用到DFS(深度优先搜索)或者BFS(广度优先搜索)。
33+
34+
在分割的过程中对于每一个字符串而言都可以分为两部分:左边一个回文串加右边一个子串,比如 "abc" 可分为 "a" + "bc" 。 然后对"bc"分割仍然是同样的方法,分为"b"+"c"。
35+
36+
在处理的时候去优先寻找更短的回文串,然后回溯找稍微长一些的回文串分割方法,不断回溯,分割,直到找到所有的分割方法。
37+
38+
举个🌰:分割"aac"。
39+
40+
1. 分割为 a + ac
41+
2. 分割为 a + a + c,分割后,得到一组结果,再回溯到 a + ac
42+
3. a + ac 中 ac 不是回文串,继续回溯,回溯到 aac
43+
4. 分割为稍长的回文串,分割为 aa + c 分割完成得到一组结果,再回溯到 aac
44+
5. aac 不是回文串,搜索结束
45+
46+
47+
48+
### 动画描述
49+
50+
![](../Animation/Animation.gif)
51+
52+
### 代码实现
53+
54+
```java
55+
class Solution {
56+
List<List<String>> res = new ArrayList<>();
57+
58+
public List<List<String>> partition(String s) {
59+
if(s==null||s.length()==0)
60+
return res;
61+
dfs(s,new ArrayList<String>(),0);
62+
return res;
63+
}
64+
65+
public void dfs(String s,List<String> remain,int left){
66+
if(left==s.length()){ //判断终止条件
67+
res.add(new ArrayList<String>(remain)); //添加到结果中
68+
return;
69+
}
70+
for(int right=left;right<s.length();right++){ //从left开始,依次判断left->right是不是回文串
71+
if(isPalindroom(s,left,right)){ //判断是否是回文串
72+
remain.add(s.substring(left,right+1)); //添加到当前回文串到list中
73+
dfs(s,remain,right+1); //从right+1开始继续递归,寻找回文串
74+
remain.remove(remain.size()-1); //回溯,从而寻找更长的回文串
75+
}
76+
}
77+
}
78+
/**
79+
* 判断是否是回文串
80+
*/
81+
public boolean isPalindroom(String s,int left,int right){
82+
while(left<right&&s.charAt(left)==s.charAt(right)){
83+
left++;
84+
right--;
85+
}
86+
return left>=right;
87+
}
88+
}
89+
```
90+
91+
![](../../Pictures/qrcode.jpg)

0136-Single-Number/Animation/136.gif

446 KB
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# LeetCode 第 136 号问题:只出现一次的数字
2+
3+
> 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一。
4+
>
5+
> 同步博客:https://www.algomooc.com
6+
7+
题目来源于 LeetCode 上第 136 号问题:只出现一次的数字。题目难度为 Easy,目前通过率为 66.8% 。
8+
9+
### 题目描述
10+
11+
给定一个**非空**整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
12+
13+
**说明:**
14+
15+
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
16+
17+
**示例 1:**
18+
19+
```
20+
输入: [2,2,1]
21+
输出: 1
22+
```
23+
24+
**示例 2:**
25+
26+
```
27+
输入: [4,1,2,1,2]
28+
输出: 4
29+
```
30+
31+
### 题目解析
32+
33+
根据题目描述,由于加上了时间复杂度必须是 O(n) ,并且空间复杂度为 O(1) 的条件,因此不能用排序方法,也不能使用 map 数据结构。
34+
35+
程序员小吴想了一下午没想出来,答案是使用 **位操作Bit Operation** 来解此题。
36+
37+
将所有元素做异或运算,即a[1] ⊕ a[2] ⊕ a[3] ⊕ …⊕ a[n],所得的结果就是那个只出现一次的数字,时间复杂度为O(n)。
38+
39+
### 异或
40+
41+
异或运算A ⊕ B的真值表如下:
42+
43+
| A | B ||
44+
| :--- | :--: | ---: |
45+
| F | F | F |
46+
| F | T | T |
47+
| T | F | T |
48+
| T | T | F |
49+
50+
### 动画演示
51+
52+
![](../Animation/136.gif)
53+
54+
### 进阶版
55+
56+
有一个 n 个元素的数组,除了两个数只出现一次外,其余元素都出现两次,让你找出这两个只出现一次的数分别是几,要求时间复杂度为 O(n) 且再开辟的内存空间固定(与 n 无关)。
57+
58+
#### 示例 :
59+
60+
输入: [1,2,2,1,3,4]
61+
输出: [3,4]
62+
63+
### 题目再解析
64+
65+
根据前面找一个不同数的思路算法,在这里把所有元素都异或,那么得到的结果就是那两个只出现一次的元素异或的结果。
66+
67+
然后,因为这两个只出现一次的元素一定是不相同的,所以这两个元素的二进制形式肯定至少有某一位是不同的,即一个为 0 ,另一个为 1 ,现在需要找到这一位。
68+
69+
根据异或的性质 `任何一个数字异或它自己都等于 0 `,得到这个数字二进制形式中任意一个为 1 的位都是我们要找的那一位。
70+
71+
再然后,以这一位是 1 还是 0 为标准,将数组的 n 个元素分成两部分。
72+
73+
- 将这一位为 0 的所有元素做异或,得出的数就是只出现一次的数中的一个
74+
- 将这一位为 1 的所有元素做异或,得出的数就是只出现一次的数中的另一个。
75+
76+
这样就解出题目。忽略寻找不同位的过程,总共遍历数组两次,时间复杂度为O(n)。
77+
78+
### 动画再演示
79+
80+
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/5uz1n.gif)
81+
82+
83+
84+
85+
86+
![](../../Pictures/qrcode.jpg)
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# LeetCode 第 138 号问题:复制带随机指针的链表
2+
3+
> 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一。
4+
>
5+
> 同步博客:https://www.algomooc.com
6+
7+
题目来源于 LeetCode 上第 138 号问题:复制带随机指针的链表。题目难度为 Medium,目前通过率为 40.5% 。
8+
9+
### 题目描述
10+
11+
给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。
12+
13+
要求返回这个链表的**深拷贝**
14+
15+
**示例:**
16+
17+
```
18+
输入:
19+
{"$id":"1","next":{"$id":"2","next":null,"random":{"$ref":"2"},"val":2},"random":{"$ref":"2"},"val":1}
20+
21+
解释:
22+
节点 1 的值是 1,它的下一个指针和随机指针都指向节点 2 。
23+
节点 2 的值是 2,它的下一个指针指向 null,随机指针指向它自己。
24+
```
25+
26+
### 题目解析
27+
28+
1. 在原链表的每个节点后面拷贝出一个新的节点
29+
30+
2. 依次给新的节点的随机指针赋值,而且这个赋值非常容易 cur->next->random = cur->random->next
31+
32+
3. 断开链表可得到深度拷贝后的新链表
33+
34+
之所以说这个方法比较巧妙是因为相较于一般的解法(如使用 Hash map )来处理,上面这个解法 **不需要占用额外的空间**
35+
36+
### 动画描述
37+
38+
![](../Animation/Animation.gif)
39+
40+
### 代码实现
41+
42+
我发现带指针的题目使用 C++ 版本更容易描述,所以下面的代码实现是 C++ 版本。
43+
44+
```c++
45+
class Solution {
46+
public:
47+
RandomListNode *copyRandomList(RandomListNode *head) {
48+
if (!head) return NULL;
49+
RandomListNode *cur = head;
50+
while (cur) {
51+
RandomListNode *node = new RandomListNode(cur->label);
52+
node->next = cur->next;
53+
cur->next = node;
54+
cur = node->next;
55+
}
56+
cur = head;
57+
while (cur) {
58+
if (cur->random) {
59+
cur->next->random = cur->random->next;
60+
}
61+
cur = cur->next->next;
62+
}
63+
cur = head;
64+
RandomListNode *res = head->next;
65+
while (cur) {
66+
RandomListNode *tmp = cur->next;
67+
cur->next = tmp->next;
68+
if(tmp->next) tmp->next = tmp->next->next;
69+
cur = cur->next;
70+
}
71+
return res;
72+
}
73+
};
74+
```
75+
76+
![](../../Pictures/qrcode.jpg)
77+
+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# LeetCode 第 139 号问题:单词拆分
2+
3+
> 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一。
4+
>
5+
> 同步博客:https://www.algomooc.com
6+
7+
题目来源于 LeetCode 上第 139 号问题:单词拆分。
8+
9+
### 题目描述
10+
11+
给定一个**非空**字符串 *s* 和一个包含**非空**单词列表的字典 *wordDict*,判定 *s* 是否可以被空格拆分为一个或多个在字典中出现的单词。
12+
13+
**说明:**
14+
15+
- 拆分时可以重复使用字典中的单词。
16+
- 你可以假设字典中没有重复的单词。
17+
18+
19+
20+
### 题目解析
21+
22+
**分割回文串** 有些类似,都是拆分,但是如果此题采取 深度优先搜索 的方法来解决的话,答案是超时的,不信的同学可以试一下~
23+
24+
为什么会超时呢?
25+
26+
因为使用 深度优先搜索 会重复的计算了有些位的可拆分情况,这种情况的优化肯定是需要 动态规划 来处理的。
27+
28+
如果不知道动态规划的,可以看一下小吴之前的万字长文,比较详细的介绍了动态规划的概念。
29+
30+
在这里,只需要去定义一个数组 boolean[] memo,其中第 i 位 memo[i] 表示待拆分字符串从第 0 位到第 i-1 位是否可以被成功地拆分。
31+
32+
然后分别计算每一位是否可以被成功地拆分。
33+
34+
35+
36+
### 动画描述
37+
38+
暂无~
39+
40+
### 代码实现
41+
42+
43+
44+
```java
45+
class Solution {
46+
public boolean wordBreak(String s, List<String> wordDict) {
47+
int n = s.length();
48+
int max_length=0;
49+
for(String temp:wordDict){
50+
max_length = temp.length() > max_length ? temp.length() : max_length;
51+
}
52+
// memo[i] 表示 s 中以 i - 1 结尾的字符串是否可被 wordDict 拆分
53+
boolean[] memo = new boolean[n + 1];
54+
memo[0] = true;
55+
for (int i = 1; i <= n; i++) {
56+
for (int j = i-1; j >= 0 && max_length >= i - j; j--) {
57+
if (memo[j] && wordDict.contains(s.substring(j, i))) {
58+
memo[i] = true;
59+
break;
60+
}
61+
}
62+
}
63+
return memo[n];
64+
}
65+
}
66+
```
67+
68+
![](../../Pictures/qrcode.jpg)
128 KB
Loading

0 commit comments

Comments
 (0)