forked from MisterBooo/LeetCodeAnimation
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
c3aa5c5
commit f104850
Showing
65 changed files
with
3,185 additions
and
0 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
91 changes: 91 additions & 0 deletions
91
0131-Palindrome-Partitioning/Article/0131-Palindrome-Partitioning.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
# LeetCode 第 131 号问题:分割回文串 | ||
|
||
> 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一。 | ||
> | ||
> 同步博客:https://www.algomooc.com | ||
|
||
题目来源于 LeetCode 上第 131 号问题:分割回文串。题目难度为 Medium,目前通过率为 45.8% 。 | ||
|
||
### 题目描述 | ||
|
||
给定一个字符串 *s*,将 *s* 分割成一些子串,使每个子串都是回文串。 | ||
|
||
返回 *s* 所有可能的分割方案。 | ||
|
||
**示例:** | ||
|
||
```yaml | ||
输入: "aab" | ||
输出: | ||
[ | ||
["aa","b"], | ||
["a","a","b"] | ||
] | ||
``` | ||
|
||
### | ||
|
||
### 题目解析 | ||
|
||
首先,对于一个字符串的分割,肯定需要将所有分割情况都遍历完毕才能判断是不是回文数。不能因为 **abba** 是回文串,就认为它的所有子串都是回文的。 | ||
|
||
既然需要将所有的分割方法都找出来,那么肯定需要用到DFS(深度优先搜索)或者BFS(广度优先搜索)。 | ||
|
||
在分割的过程中对于每一个字符串而言都可以分为两部分:左边一个回文串加右边一个子串,比如 "abc" 可分为 "a" + "bc" 。 然后对"bc"分割仍然是同样的方法,分为"b"+"c"。 | ||
|
||
在处理的时候去优先寻找更短的回文串,然后回溯找稍微长一些的回文串分割方法,不断回溯,分割,直到找到所有的分割方法。 | ||
|
||
举个🌰:分割"aac"。 | ||
|
||
1. 分割为 a + ac | ||
2. 分割为 a + a + c,分割后,得到一组结果,再回溯到 a + ac | ||
3. a + ac 中 ac 不是回文串,继续回溯,回溯到 aac | ||
4. 分割为稍长的回文串,分割为 aa + c 分割完成得到一组结果,再回溯到 aac | ||
5. aac 不是回文串,搜索结束 | ||
|
||
|
||
|
||
### 动画描述 | ||
|
||
![](../Animation/Animation.gif) | ||
|
||
### 代码实现 | ||
|
||
```java | ||
class Solution { | ||
List<List<String>> res = new ArrayList<>(); | ||
|
||
public List<List<String>> partition(String s) { | ||
if(s==null||s.length()==0) | ||
return res; | ||
dfs(s,new ArrayList<String>(),0); | ||
return res; | ||
} | ||
|
||
public void dfs(String s,List<String> remain,int left){ | ||
if(left==s.length()){ //判断终止条件 | ||
res.add(new ArrayList<String>(remain)); //添加到结果中 | ||
return; | ||
} | ||
for(int right=left;right<s.length();right++){ //从left开始,依次判断left->right是不是回文串 | ||
if(isPalindroom(s,left,right)){ //判断是否是回文串 | ||
remain.add(s.substring(left,right+1)); //添加到当前回文串到list中 | ||
dfs(s,remain,right+1); //从right+1开始继续递归,寻找回文串 | ||
remain.remove(remain.size()-1); //回溯,从而寻找更长的回文串 | ||
} | ||
} | ||
} | ||
/** | ||
* 判断是否是回文串 | ||
*/ | ||
public boolean isPalindroom(String s,int left,int right){ | ||
while(left<right&&s.charAt(left)==s.charAt(right)){ | ||
left++; | ||
right--; | ||
} | ||
return left>=right; | ||
} | ||
} | ||
``` | ||
|
||
![](../../Pictures/qrcode.jpg) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
# LeetCode 第 136 号问题:只出现一次的数字 | ||
|
||
> 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一。 | ||
> | ||
> 同步博客:https://www.algomooc.com | ||
|
||
题目来源于 LeetCode 上第 136 号问题:只出现一次的数字。题目难度为 Easy,目前通过率为 66.8% 。 | ||
|
||
### 题目描述 | ||
|
||
给定一个**非空**整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。 | ||
|
||
**说明:** | ||
|
||
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗? | ||
|
||
**示例 1:** | ||
|
||
``` | ||
输入: [2,2,1] | ||
输出: 1 | ||
``` | ||
|
||
**示例 2:** | ||
|
||
``` | ||
输入: [4,1,2,1,2] | ||
输出: 4 | ||
``` | ||
|
||
### 题目解析 | ||
|
||
根据题目描述,由于加上了时间复杂度必须是 O(n) ,并且空间复杂度为 O(1) 的条件,因此不能用排序方法,也不能使用 map 数据结构。 | ||
|
||
程序员小吴想了一下午没想出来,答案是使用 **位操作Bit Operation** 来解此题。 | ||
|
||
将所有元素做异或运算,即a[1] ⊕ a[2] ⊕ a[3] ⊕ …⊕ a[n],所得的结果就是那个只出现一次的数字,时间复杂度为O(n)。 | ||
|
||
### 异或 | ||
|
||
异或运算A ⊕ B的真值表如下: | ||
|
||
| A | B | ⊕ | | ||
| :--- | :--: | ---: | | ||
| F | F | F | | ||
| F | T | T | | ||
| T | F | T | | ||
| T | T | F | | ||
|
||
### 动画演示 | ||
|
||
![](../Animation/136.gif) | ||
|
||
### 进阶版 | ||
|
||
有一个 n 个元素的数组,除了两个数只出现一次外,其余元素都出现两次,让你找出这两个只出现一次的数分别是几,要求时间复杂度为 O(n) 且再开辟的内存空间固定(与 n 无关)。 | ||
|
||
#### 示例 : | ||
|
||
输入: [1,2,2,1,3,4] | ||
输出: [3,4] | ||
|
||
### 题目再解析 | ||
|
||
根据前面找一个不同数的思路算法,在这里把所有元素都异或,那么得到的结果就是那两个只出现一次的元素异或的结果。 | ||
|
||
然后,因为这两个只出现一次的元素一定是不相同的,所以这两个元素的二进制形式肯定至少有某一位是不同的,即一个为 0 ,另一个为 1 ,现在需要找到这一位。 | ||
|
||
根据异或的性质 `任何一个数字异或它自己都等于 0 `,得到这个数字二进制形式中任意一个为 1 的位都是我们要找的那一位。 | ||
|
||
再然后,以这一位是 1 还是 0 为标准,将数组的 n 个元素分成两部分。 | ||
|
||
- 将这一位为 0 的所有元素做异或,得出的数就是只出现一次的数中的一个 | ||
- 将这一位为 1 的所有元素做异或,得出的数就是只出现一次的数中的另一个。 | ||
|
||
这样就解出题目。忽略寻找不同位的过程,总共遍历数组两次,时间复杂度为O(n)。 | ||
|
||
### 动画再演示 | ||
|
||
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/5uz1n.gif) | ||
|
||
|
||
|
||
|
||
|
||
![](../../Pictures/qrcode.jpg) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
77 changes: 77 additions & 0 deletions
77
0138-Copy-List-with-Random-Pointer/Article/0138-Copy-List-with-Random-Pointer.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
# LeetCode 第 138 号问题:复制带随机指针的链表 | ||
|
||
> 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一。 | ||
> | ||
> 同步博客:https://www.algomooc.com | ||
|
||
题目来源于 LeetCode 上第 138 号问题:复制带随机指针的链表。题目难度为 Medium,目前通过率为 40.5% 。 | ||
|
||
### 题目描述 | ||
|
||
给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。 | ||
|
||
要求返回这个链表的**深拷贝**。 | ||
|
||
**示例:** | ||
|
||
``` | ||
输入: | ||
{"$id":"1","next":{"$id":"2","next":null,"random":{"$ref":"2"},"val":2},"random":{"$ref":"2"},"val":1} | ||
|
||
解释: | ||
节点 1 的值是 1,它的下一个指针和随机指针都指向节点 2 。 | ||
节点 2 的值是 2,它的下一个指针指向 null,随机指针指向它自己。 | ||
``` | ||
|
||
### 题目解析 | ||
|
||
1. 在原链表的每个节点后面拷贝出一个新的节点 | ||
|
||
2. 依次给新的节点的随机指针赋值,而且这个赋值非常容易 cur->next->random = cur->random->next | ||
|
||
3. 断开链表可得到深度拷贝后的新链表 | ||
|
||
之所以说这个方法比较巧妙是因为相较于一般的解法(如使用 Hash map )来处理,上面这个解法 **不需要占用额外的空间**。 | ||
|
||
### 动画描述 | ||
|
||
![](../Animation/Animation.gif) | ||
|
||
### 代码实现 | ||
|
||
我发现带指针的题目使用 C++ 版本更容易描述,所以下面的代码实现是 C++ 版本。 | ||
|
||
```c++ | ||
class Solution { | ||
public: | ||
RandomListNode *copyRandomList(RandomListNode *head) { | ||
if (!head) return NULL; | ||
RandomListNode *cur = head; | ||
while (cur) { | ||
RandomListNode *node = new RandomListNode(cur->label); | ||
node->next = cur->next; | ||
cur->next = node; | ||
cur = node->next; | ||
} | ||
cur = head; | ||
while (cur) { | ||
if (cur->random) { | ||
cur->next->random = cur->random->next; | ||
} | ||
cur = cur->next->next; | ||
} | ||
cur = head; | ||
RandomListNode *res = head->next; | ||
while (cur) { | ||
RandomListNode *tmp = cur->next; | ||
cur->next = tmp->next; | ||
if(tmp->next) tmp->next = tmp->next->next; | ||
cur = cur->next; | ||
} | ||
return res; | ||
} | ||
}; | ||
``` | ||
|
||
![](../../Pictures/qrcode.jpg) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
# LeetCode 第 139 号问题:单词拆分 | ||
|
||
> 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一。 | ||
> | ||
> 同步博客:https://www.algomooc.com | ||
|
||
题目来源于 LeetCode 上第 139 号问题:单词拆分。 | ||
|
||
### 题目描述 | ||
|
||
给定一个**非空**字符串 *s* 和一个包含**非空**单词列表的字典 *wordDict*,判定 *s* 是否可以被空格拆分为一个或多个在字典中出现的单词。 | ||
|
||
**说明:** | ||
|
||
- 拆分时可以重复使用字典中的单词。 | ||
- 你可以假设字典中没有重复的单词。 | ||
|
||
|
||
|
||
### 题目解析 | ||
|
||
与 **分割回文串** 有些类似,都是拆分,但是如果此题采取 深度优先搜索 的方法来解决的话,答案是超时的,不信的同学可以试一下~ | ||
|
||
为什么会超时呢? | ||
|
||
因为使用 深度优先搜索 会重复的计算了有些位的可拆分情况,这种情况的优化肯定是需要 动态规划 来处理的。 | ||
|
||
如果不知道动态规划的,可以看一下小吴之前的万字长文,比较详细的介绍了动态规划的概念。 | ||
|
||
在这里,只需要去定义一个数组 boolean[] memo,其中第 i 位 memo[i] 表示待拆分字符串从第 0 位到第 i-1 位是否可以被成功地拆分。 | ||
|
||
然后分别计算每一位是否可以被成功地拆分。 | ||
|
||
|
||
|
||
### 动画描述 | ||
|
||
暂无~ | ||
|
||
### 代码实现 | ||
|
||
|
||
|
||
```java | ||
class Solution { | ||
public boolean wordBreak(String s, List<String> wordDict) { | ||
int n = s.length(); | ||
int max_length=0; | ||
for(String temp:wordDict){ | ||
max_length = temp.length() > max_length ? temp.length() : max_length; | ||
} | ||
// memo[i] 表示 s 中以 i - 1 结尾的字符串是否可被 wordDict 拆分 | ||
boolean[] memo = new boolean[n + 1]; | ||
memo[0] = true; | ||
for (int i = 1; i <= n; i++) { | ||
for (int j = i-1; j >= 0 && max_length >= i - j; j--) { | ||
if (memo[j] && wordDict.contains(s.substring(j, i))) { | ||
memo[i] = true; | ||
break; | ||
} | ||
} | ||
} | ||
return memo[n]; | ||
} | ||
} | ||
``` | ||
|
||
![](../../Pictures/qrcode.jpg) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.