整理部分文件

This commit is contained in:
程序员吴师兄 2020-04-16 20:50:43 +08:00
parent 1a2d73936f
commit fb2465e289
27 changed files with 1825 additions and 21 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 KiB

View File

@ -0,0 +1,69 @@
# LeetCode 1 号问题两数之和
> 本文首发于公众号图解面试算法 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一
>
> 同步博客https://www.algomooc.com
>
题目来源于 LeetCode 上第 1 号问题两数之和题目难度为 Easy目前通过率为 45.8%
### 题目描述
给定一个整数数组 `nums` 和一个目标值 `target`请你在该数组中找出和为目标值的那 **两个** 整数并返回他们的数组下标
你可以假设每种输入只会对应一个答案但是你不能重复利用这个数组中同样的元素
**示例:**
```
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
```
### 题目解析
使用查找表来解决该问题
设置一个 map 容器 record 用来记录元素的值与索引然后遍历数组 nums
* 每次遍历时使用临时变量 complement 用来保存目标值与当前值的差值
* 在此次遍历中查找 record 查看是否有与 complement 一致的值如果查找成功则返回查找值的索引值与当前变量的值 i
* 如果未找到则在 record 保存该元素与索引值 i
### 动画描述
![](../Animation/animation.gif)
### 代码实现
```
// 1. Two Sum
// https://leetcode.com/problems/two-sum/description/
// 时间复杂度O(n)
// 空间复杂度O(n)
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int> record;
for(int i = 0 ; i < nums.size() ; i ++){
int complement = target - nums[i];
if(record.find(complement) != record.end()){
int res[] = {i, record[complement]};
return vector<int>(res, res + 2);
}
record[nums[i]] = i;
}
}
};
```
![](../../Pictures/qrcode.jpg)

Binary file not shown.

After

Width:  |  Height:  |  Size: 305 KiB

View File

@ -0,0 +1,77 @@
# LeetCode 2 号问题两数相加
> 本文首发于公众号图解面试算法 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一
>
> 同步博客https://www.algomooc.com
题目来源于 LeetCode 上第 2 号问题两数相加题目难度为 Medium目前通过率为 33.9%
### 题目描述
给出两个 **非空** 的链表用来表示两个非负的整数其中它们各自的位数是按照 **逆序** 的方式存储的并且它们的每个节点只能存储 **一位** 数字
如果我们将这两个数相加起来则会返回一个新的链表来表示它们的和
您可以假设除了数字 0 之外这两个数都不会以 0 开头
**示例**
```
输入(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出7 -> 0 -> 8
原因342 + 465 = 807
```
### 题目解析
设立一个表示进位的变量`carried`建立一个新链表把输入的两个链表从头往后同时处理每两个相加将结果加上`carried`后的值作为一个新节点到新链表后面
### 动画描述
![](../Animation/animation.gif)
### 代码实现
```
/// 时间复杂度: O(n)
/// 空间复杂度: O(n)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode *p1 = l1, *p2 = l2;
ListNode *dummyHead = new ListNode(-1);
ListNode* cur = dummyHead;
int carried = 0;
while(p1 || p2 ){
int a = p1 ? p1->val : 0;
int b = p2 ? p2->val : 0;
cur->next = new ListNode((a + b + carried) % 10);
carried = (a + b + carried) / 10;
cur = cur->next;
p1 = p1 ? p1->next : NULL;
p2 = p2 ? p2->next : NULL;
}
cur->next = carried ? new ListNode(1) : NULL;
ListNode* ret = dummyHead->next;
delete dummyHead;
return ret;
}
};
```
![](../../Pictures/qrcode.jpg)

View File

@ -0,0 +1,66 @@
# LeetCode 3 号问题无重复字符的最长子串
> 本文首发于公众号图解面试算法 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一
>
> 同步博客https://www.algomooc.com
题目来源于 LeetCode 上第 3 号问题无重复字符的最长子串题目难度为 Medium目前通过率为 29.0%
### 题目描述
给定一个字符串请你找出其中不含有重复字符的 **最长子串** 的长度
**示例 1:**
```java
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc"所以其长度为 3
```
### 题目解析
建立一个256位大小的整型数组 freg 用来建立字符和其出现位置之间的映射
维护一个滑动窗口窗口内的都是没有重复的字符去尽可能的扩大窗口的大小窗口不停的向右滑动
- 1如果当前遍历到的字符从未出现过那么直接扩大右边界
- 2如果当前遍历到的字符出现过则缩小窗口左边索引向右移动然后继续观察当前遍历到的字符
- 3重复12直到左边索引无法再移动
- 4维护一个结果res每次用出现过的窗口大小来更新结果 res最后返回 res 获取结果
### 动画描述
![动画描述](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/20ahe.gif)
### 代码实现
```c++
// 滑动窗口
// 时间复杂度: O(len(s))
// 空间复杂度: O(len(charset))
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int freq[256] = {0};
int l = 0, r = -1; //滑动窗口为s[l...r]
int res = 0;
// 整个循环从 l == 0; r == -1 这个空窗口开始
// 到l == s.size(); r == s.size()-1 这个空窗口截止
// 在每次循环里逐渐改变窗口, 维护freq, 并记录当前窗口中是否找到了一个新的最优值
while(l < s.size()){
if(r + 1 < s.size() && freq[s[r+1]] == 0){
r++;
freq[s[r]]++;
}else { //r已经到头 || freq[s[r+1]] == 1
freq[s[l]]--;
l++;
}
res = max(res, r-l+1);
}
return res;
}
};
```
![](../../Pictures/qrcode.jpg)

View File

@ -0,0 +1,142 @@
# LeetCode 9 号问题回文数
> 本文首发于公众号图解面试算法 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一
>
> 同步博客https://www.algomooc.com
题目来源于 LeetCode 9 号问题回文数题目难度为 Easy目前通过率为 56.0%
## 题目描述
判断一个整数是否是回文数回文数是指正序从左向右和倒序从右向左读都是一样的整数
**示例 1:**
```
输入: 121
输出: true
```
**示例 2:**
```
输入: -121
输出: false
解释: 从左向右读, -121 从右向左读, 121- 因此它不是一个回文数
```
**示例 3:**
```
输入: 10
输出: false
解释: 从右向左读, 01 因此它不是一个回文数
```
**进阶:**
你能不将整数转为字符串来解决这个问题吗
## 题目解析
### 解法一普通解法
最好理解的一种解法就是先将 **整数转为字符串** 然后将字符串分割为数组只需要循环数组的一半长度进行判断对应元素是否相等即可
#### 动画描述
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/ods8b.gif)
#### 代码实现
```java
///简单粗暴看看就行
class Solution {
public boolean isPalindrome(int x) {
String reversedStr = (new StringBuilder(x + "")).reverse().toString();
return (x + "").equals(reversedStr);
}
}
```
### 解法二进阶解法---数学解法
通过取整和取余操作获取整数中对应的数字进行比较
举个例子1221 这个数字
- 通过计算 1221 / 1000 得首位1
- 通过计算 1221 % 10 可得末位 1
- 进行比较
- 再将 22 取出来继续比较
#### 动画描述
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/v3tkl.gif)
#### 代码实现
```java
class Solution {
public boolean isPalindrome(int x) {
//边界判断
if (x < 0) return false;
int div = 1;
//
while (x / div >= 10) div *= 10;
while (x > 0) {
int left = x / div;
int right = x % 10;
if (left != right) return false;
x = (x % div) / 10;
div /= 100;
}
return true;
}
}
```
### 解法三进阶解法---巧妙解法
直观上来看待回文数的话就感觉像是将数字进行对折后看能否一一对应
所以这个解法的操作就是 **取出后半段数字进行翻转**
这里需要注意的一个点就是由于回文数的位数可奇可偶所以当它的长度是偶数时它对折过来应该是相等的当它的长度是奇数时那么它对折过来后有一个的长度需要去掉一位数除以 10 并取整
具体做法如下
- 每次进行取余操作 %10取出最低的数字`y = x % 10`
- 将最低的数字加到取出数的末尾`revertNum = revertNum * 10 + y`
- 每取一个最低位数字x 都要自除以 10
- 判断 `x` 是不是小于 `revertNum` 当它小于的时候说明数字已经对半或者过半了
- 最后判断奇偶数情况如果是偶数的话revertNum x 相等如果是奇数的话最中间的数字就在revertNum 的最低位上将它除以 10 以后应该和 x 相等
#### 动画描述
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/0siv7.png)
#### 代码实现
```java
class Solution {
public boolean isPalindrome(int x) {
//思考这里大家可以思考一下为什么末尾为 0 就可以直接返回 false
if (x < 0 || (x % 10 == 0 && x != 0)) return false;
int revertedNumber = 0;
while (x > revertedNumber) {
revertedNumber = revertedNumber * 10 + x % 10;
x /= 10;
}
return x == revertedNumber || x == revertedNumber / 10;
}
}
```
![](../../Pictures/qrcode.jpg)

View File

@ -0,0 +1,54 @@
# LeetCode 15 号问题三数之和
> 本文首发于公众号图解面试算法 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一
>
> 同步博客https://www.algomooc.com
题目来源于 LeetCode 上第 15 号问题三数之和
### 题目描述
给定一个包含 *n* 个整数的数组 `nums`判断 `nums` 中是否存在三个元素 *abc *使得 *a + b + c =* 0 找出所有满足条件且不重复的三元组
### 题目解析
题目需要我们找出三个数且和为 0 那么除了三个数全是 0 的情况之外肯定会有负数和正数所以一开始可以先选择一个数然后再去找另外两个数这样只要找到两个数且和为第一个选择的数的相反数就行了也就是说需要枚举 a b c 的存入 map 即可
需要注意的是返回的结果中不能有有重复的结果这样的代码时间复杂度是 O(n^2)在这里可以先将原数组进行排序然后再遍历排序后的数组这样就可以使用双指针以线性时间复杂度来遍历所有满足题意的两个数组合
### 动画描述
待补充
### 代码实现
###
```c++
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
sort(nums.begin(), nums.end());
if (nums.empty() || nums.back() < 0 || nums.front() > 0) return {};
for (int k = 0; k < nums.size(); ++k) {
if (nums[k] > 0) break;
if (k > 0 && nums[k] == nums[k - 1]) continue;
int target = 0 - nums[k];
int i = k + 1, j = nums.size() - 1;
while (i < j) {
if (nums[i] + nums[j] == target) {
res.push_back({nums[k], nums[i], nums[j]});
while (i < j && nums[i] == nums[i + 1]) ++i;
while (i < j && nums[j] == nums[j - 1]) --j;
++i; --j;
} else if (nums[i] + nums[j] < target) ++i;
else --j;
}
}
return res;
}
};
```
![](../../Pictures/qrcode.jpg)

View File

@ -0,0 +1,78 @@
# LeetCode 19 号问题删除链表的倒数第 N 个节点
> 本文首发于公众号图解面试算法 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一
>
> 同步博客https://www.algomooc.com
题目来源于 LeetCode 上第 19 号问题删除链表的倒数第 N 个节点题目难度为 Medium目前通过率为 34.4%
### 题目描述
给定一个链表删除链表的倒数第 *n* 个节点并且返回链表的头结点
**示例**
```
给定一个链表: 1->2->3->4->5, n = 2.
当删除了倒数第二个节点后链表变为 1->2->3->5.
```
**说明**
给定的 *n* 保证是有效的
**进阶**
你能尝试使用一趟扫描实现吗
### 题目解析
采取双重遍历肯定是可以解决问题的但题目要求我们一次遍历解决问题那我们的思路得发散一下
我们可以设想假设设定了双指针`p``q`的话`q`指向末尾的`NULL``p``q`之间相隔的元素个数为`n`那么删除掉`p`的下一个指针就完成了要求
- 设置虚拟节点`dummyHead`指向`head`
- 设定双指针`p``q`初始都指向虚拟节点`dummyHead`
- 移动`q`直到`p``q`之间相隔的元素个数为`n`
- 同时移动`p``q`直到`q`指向的为`NULL`
- `p`的下一个节点指向下下个节点
### 动画描述
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/r04hv.gif)
### 代码实现
```
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
ListNode* p = dummyHead;
ListNode* q = dummyHead;
for( int i = 0 ; i < n + 1 ; i ++ ){
q = q->next;
}
while(q){
p = p->next;
q = q->next;
}
ListNode* delNode = p->next;
p->next = delNode->next;
delete delNode;
ListNode* retNode = dummyHead->next;
delete dummyHead;
return retNode;
}
};
```
![](../../Pictures/qrcode.jpg)

View File

@ -0,0 +1,113 @@
# LeetCode 20 号问题有效的括号
> 本文首发于公众号图解面试算法 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一
>
> 同步博客https://www.algomooc.com
题目来源于 LeetCode 上第 20 号问题有效的括号题目难度为 Easy目前通过率为 37.8%
### 题目描述
给定一个只包括 `'('``')'``'{'``'}'``'['``']'` 的字符串判断字符串是否有效
有效字符串需满足
1. 左括号必须用相同类型的右括号闭合
2. 左括号必须以正确的顺序闭合
注意空字符串可被认为是有效字符串
**示例 1:**
```
输入: "()"
输出: true
```
**示例 2:**
```
输入: "()[]{}"
输出: true
```
**示例 3:**
```
输入: "(]"
输出: false
```
**示例 4:**
```
输入: "([)]"
输出: false
```
**示例 5:**
```
输入: "{[]}"
输出: true
```
### 题目解析
这道题让我们验证输入的字符串是否为括号字符串包括大括号中括号和小括号
这里我们使用****
- 遍历输入字符串
- 如果当前字符为左半边括号时则将其压入栈中
- 如果遇到右半边括号时**分类讨论**
- 1如栈不为空且为对应的左半边括号则取出栈顶元素继续循环
- 2若此时栈为空则直接返回false
- 3若不为对应的左半边括号反之返回false
### 动画描述
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/xu55u.gif)
### 代码实现
```
class Solution {
public:
bool isValid(string s) {
stack<char> stack;
for( int i = 0 ; i < s.size() ; i ++ )
if( s[i] == '(' || s[i] == '{' || s[i] == '[')
stack.push(s[i]);
else{
if( stack.size() == 0 )
return false;
char c = stack.top();
stack.pop();
char match;
if( s[i] == ')' ){
match = '(';
}
else if( s[i] == ']' ){
match = '[';
}
else{
match = '{';
}
if(c != match) return false;
}
if( stack.size() != 0 )
return false;
return true;
}
};
```
![](../../Pictures/qrcode.jpg)

View File

@ -0,0 +1,103 @@
# LeetCode 21 号问题合并两个有序链表
> 本文首发于公众号图解面试算法 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一
>
> 同步博客https://www.algomooc.com
题目来源于 LeetCode 上第 21 号问题合并两个有序链表题目难度为 Easy目前通过率为 45.8%
### 题目描述
将两个有序链表合并为一个新的有序链表并返回新链表是通过拼接给定的两个链表的所有节点组成的
**示例**
```
输入1->2->4, 1->3->4
输出1->1->2->3->4->4
```
### 题目解析
#### 一般方案
##### 1.1 解题思想
> 1对空链表存在的情况进行处理假如 pHead1 为空则返回 pHead2 pHead2 为空则返回 pHead1两个都为空此情况在pHead1为空已经被拦截
> 2在两个链表无空链表的情况下确定第一个结点比较链表1和链表2的第一个结点的值将值小的结点保存下来为合并后的第一个结点并且把第一个结点为最小的链表向后移动一个元素
> 3继续在剩下的元素中选择小的值连接到第一个结点后面并不断next将值小的结点连接到第一个结点后面直到某一个链表为空
> 4当两个链表长度不一致时也就是比较完成后其中一个链表为空此时需要把另外一个链表剩下的元素都连接到第一个结点的后面
##### 1.2 代码实现
```c++
ListNode* mergeTwoOrderedLists(ListNode* pHead1, ListNode* pHead2){
ListNode* pTail = NULL;//指向新链表的最后一个结点 pTail->next去连接
ListNode* newHead = NULL;//指向合并后链表第一个结点
if (NULL == pHead1){
return pHead2;
}else if(NULL == pHead2){
return pHead1;
}else{
//确定头指针
if ( pHead1->data < pHead2->data){
newHead = pHead1;
pHead1 = pHead1->next;//指向链表的第二个结点
}else{
newHead = pHead2;
pHead2 = pHead2->next;
}
pTail = newHead;//指向第一个结点
while ( pHead1 && pHead2) {
if ( pHead1->data <= pHead2->data ){
pTail->next = pHead1;
pHead1 = pHead1->next;
}else {
pTail->next = pHead2;
pHead2 = pHead2->next;
}
pTail = pTail->next;
}
if(NULL == pHead1){
pTail->next = pHead2;
}else if(NULL == pHead2){
pTail->next = pHead1;
}
return newHead;
}
```
#### 2 递归方案
##### 2.1 解题思想
> 1对空链表存在的情况进行处理假如 pHead1 为空则返回 pHead2 pHead2 为空则返回 pHead1
> 2比较两个链表第一个结点的大小确定头结点的位置
> 3头结点确定后继续在剩下的结点中选出下一个结点去链接到第二步选出的结点后面然后在继续重复2 3 直到有链表为空
##### 2.2 代码实现
```c++
ListNode* mergeTwoOrderedLists(ListNode* pHead1, ListNode* pHead2){
ListNode* newHead = NULL;
if (NULL == pHead1){
return pHead2;
}else if(NULL ==pHead2){
return pHead1;
}else{
if (pHead1->data < pHead2->data){
newHead = pHead1;
newHead->next = mergeTwoOrderedLists(pHead1->next, pHead2);
}else{
newHead = pHead2;
newHead->next = mergeTwoOrderedLists(pHead1, pHead2->next);
}
return newHead;
}
}
```
![](../../Pictures/qrcode.jpg)

View File

@ -0,0 +1,187 @@
# LeetCode 23 号问题合并 K 个排序链表
> 本文首发于公众号图解面试算法 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一
>
> 同步博客https://www.algomooc.com
题目来源于 LeetCode 上第 23 号问题合并 K 个排序链表题目难度为 Hard目前通过率为 45.8%
### 题目描述
合并 *k* 个排序链表返回合并后的排序链表请分析和描述算法的复杂度
**示例:**
```
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
```
**输入**
![图一](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/u2jnp.jpg)
**输出**
![图二](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/yc4ac.jpg)
### 题目解析
### 题目分析一
这里需要将这 *k* 个排序链表整合成一个排序链表也就是说有多个输入一个输出类似于漏斗一样的概念
因此可以利用最小堆的概念如果你对堆的概念不熟悉可以戳这先了解一下~
取每个 Linked List 的最小节点放入一个 heap 排序成最小堆然后取出堆顶最小的元素放入输出的合并 List 然后将该节点在其对应的 List 中的下一个节点插入到 heap 循环上面步骤以此类推直到全部节点都经过 heap
由于 heap 的大小为始终为 k 而每次插入的复杂度是 logk 一共插入了 nk 个节点时间复杂度为 O(nklogk)空间复杂度为O(k)
### 动画演示
![动画演示](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/iuxmh.gif)
### 代码实现
```java
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
//用heap()这种数据结构也就是 java 里面的 PriorityQueue
PriorityQueue<ListNode> pq = new PriorityQueue<>(new Comparator<ListNode>() {
public int compare(ListNode a, ListNode b) {
return a.val-b.val;
}
});
ListNode ret = null, cur = null;
for(ListNode node: lists) {
if(null != node) {
pq.add(node);
}
}
while(!pq.isEmpty()) {
ListNode node = pq.poll();
if(null == ret) {
ret = cur = node;
}
else {
cur = cur.next = node;
}
if(null != node.next) {
pq.add(node.next);
}
}
return ret;
}
}
```
### 题目分析二
这道题需要合并 k 个有序链表并且最终合并出来的结果也必须是有序的如果一开始没有头绪的话可以先从简单的开始**合并 个有序链表**
合并两个有序链表将两个有序链表合并为一个新的有序链表并返回新链表是通过拼接给定的两个链表的所有节点组成的
**示例**
```
输入1->2->4, 1->3->4
输出1->1->2->3->4->4
```
这道题目按照题目描述做下去就行新建一个链表比较原始两个链表中的元素值把较小的那个链到新链表中即可需要注意的一点时由于两个输入链表的长度可能不同所以最终会有一个链表先完成插入所有元素则直接另一个未完成的链表直接链入新链表的末尾
所以代码实现很容易写
```java
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
//新建链表
ListNode dummyHead = new ListNode(0);
ListNode cur = dummyHead;
while (l1 != null && l2 != null) {
if (l1.val < l2.val) {
cur.next = l1;
cur = cur.next;
l1 = l1.next;
} else {
cur.next = l2;
cur = cur.next;
l2 = l2.next;
}
}
// 注意点当有链表为空时直接连接另一条链表
if (l1 == null) {
cur.next = l2;
} else {
cur.next = l1;
}
return dummyHead.next;
}
```
现在回到一开始的题目合并 K 个排序链表
**合并 K 个排序链表** **合并两个有序链表** 的区别点在于操作有序链表的数量上因此完全可以按照上面的代码思路来实现合并 K 个排序链表
这里可以参考 **归并排序 **的分治思想将这 K 个链表先划分为两个 K/2 个链表处理它们的合并然后不停的往下划分直到划分成只有一个或两个链表的任务开始合并
![归并-分治](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/74ush.gif)
### 代码实现
根据上面的动画实现代码非常简单也容易理解先划分直到不能划分下去然后开始合并
```java
class Solution {
public ListNode mergeKLists(ListNode[] lists){
if(lists.length == 0)
return null;
if(lists.length == 1)
return lists[0];
if(lists.length == 2){
return mergeTwoLists(lists[0],lists[1]);
}
int mid = lists.length/2;
ListNode[] l1 = new ListNode[mid];
for(int i = 0; i < mid; i++){
l1[i] = lists[i];
}
ListNode[] l2 = new ListNode[lists.length-mid];
for(int i = mid,j=0; i < lists.length; i++,j++){
l2[j] = lists[i];
}
return mergeTwoLists(mergeKLists(l1),mergeKLists(l2));
}
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1 == null) return l2;
if (l2 == null) return l1;
ListNode head = null;
if (l1.val <= l2.val){
head = l1;
head.next = mergeTwoLists(l1.next, l2);
} else {
head = l2;
head.next = mergeTwoLists(l1, l2.next);
}
return head;
}
}
```
![](../../Pictures/qrcode.jpg)

View File

@ -0,0 +1,75 @@
# LeetCode 24 号问题两两交换链表中的节点
> 本文首发于公众号图解面试算法 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一
>
> 同步博客https://www.algomooc.com
题目来源于 LeetCode 上第 24 号问题两两交换链表中的节点题目难度为 Medium目前通过率为 45.8%
### 题目描述
给定一个链表两两交换其中相邻的节点并返回交换后的链表
**你不能只是单纯的改变节点内部的值**而是需要实际的进行节点交换
**示例:**
```
给定 1->2->3->4, 你应该返回 2->1->4->3.
```
### 题目解析
该题属于基本的链表操作题
- 设置一个虚拟头结点`dummyHead `
- 设置需要交换的两个节点分别为`node1 ``node2`同时设置`node2`的下一个节点`next`
##### 在这一轮操作中
- `node2`节点的next设置为`node1`节点
- `node1`节点的next设置为`next `节点
- `dummyHead `节点的next设置为`node2 `
- 结束本轮操作
接下来的每轮操作都按照上述进行
### 动画描述
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/6kpyu.gif)
### 代码实现
```
// 24. Swap Nodes in Pairs
// https://leetcode.com/problems/swap-nodes-in-pairs/description/
// 时间复杂度: O(n)
// 空间复杂度: O(1)
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
ListNode* p = dummyHead;
while(p->next && p->next->next){
ListNode* node1 = p->next;
ListNode* node2 = node1->next;
ListNode* next = node2->next;
node2->next = node1;
node1->next = next;
p->next = node2;
p = node1;
}
ListNode* retHead = dummyHead->next;
delete dummyHead;
return retHead;
}
};
```
![](../../Pictures/qrcode.jpg)

View File

@ -0,0 +1,91 @@
# LeetCode 26 号问题删除排序数组中的重复项
> 本文首发于公众号图解面试算法 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一
>
> 同步博客https://www.algomooc.com
题目来源于 LeetCode 上第 26 号问题删除排序数组中的重复项题目难度为 Easy目前通过率为 48.8%
### 题目描述
给定一个排序数组你需要在**原地**删除重复出现的元素使得每个元素只出现一次返回移除后数组的新长度
不要使用额外的数组空间你必须在**原地修改输入数组**并在使用 O(1) 额外空间的条件下完成
**示例 1:**
```
给定数组 nums = [1,1,2],
函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2
你不需要考虑数组中超出新长度后面的元素
```
**示例 2:**
```
给定 nums = [0,0,1,1,1,2,2,3,3,4],
函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4
你不需要考虑数组中超出新长度后面的元素
```
**说明:**
为什么返回数值是整数但输出的答案是数组呢?
请注意输入数组是以**引用**方式传递的这意味着在函数里修改输入数组对于调用者是可见的
你可以想象内部操作如下:
```
// nums 是以引用方式传递的也就是说不对实参做任何拷贝
int len = removeDuplicates(nums);
// 在函数里修改输入数组对于调用者是可见的
// 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素
for (int i = 0; i < len; i++) {
print(nums[i]);
}
```
### 题目解析
使用快慢指针来记录遍历的坐标
- 开始时这两个指针都指向第一个数字
- 如果两个指针指的数字相同则快指针向前走一步
- 如果不同则两个指针都向前走一步
- 当快指针走完整个数组后慢指针当前的坐标加1就是数组中不同数字的个数
### 动画描述
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/4y1ec.gif)
### 代码实现
```
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
if (nums.empty()) return 0;
int pre = 0, cur = 0, n = nums.size();
while (cur < n) {
if (nums[pre] == nums[cur]){
cur++;
} else{
++pre;
nums[pre] = nums[cur];
cur++;
}
}
return pre + 1;
}
};
```
![](../../Pictures/qrcode.jpg)

View File

@ -0,0 +1,90 @@
# LeetCode 66 号问题加一
> 本文首发于公众号图解面试算法 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一
>
> 同步博客https://www.algomooc.com
今天分享的题目来源于 LeetCode 上第 66 号问题加一题目难度为 Easy目前通过率为 39.0%
### 题目描述
给定一个由**整数**组成的**非空**数组所表示的非负整数在该数的基础上加一
最高位数字存放在数组的首位 数组中每个元素只存储一个数字
你可以假设除了整数 0 之外这个整数不会以零开头
**示例 1:**
```
输入: [1,2,3]
输出: [1,2,4]
解释: 输入数组表示数字 123
```
**示例 2:**
```
输入: [4,3,2,1]
输出: [4,3,2,2]
解释: 输入数组表示数字 4321
```
**示例 3:**
```
//为了更好理解题意根据 LeetCode 评论区评论新增一个示例
输入: [9,9]
输出: [100]
解释: 输入数组表示数字 100
```
### 题目解析
本题很简单题目意思也很好理解注意的点就是 **进位问题**
* 如果数组末位个位小于 9 直接个位加 1 返回即可
* 如果数组末位个位等于 9将该位个位设置为 0 并且产生了进位接下来观察前一位十位
* * 如果前一位十位小于 9 直接十位加 1 返回即可
* 如果前一位十位等于 9将该位十位设置为 0 并且产生了进位接下来观察前一位百位
* 以此类推最后观察运算完的第一位是否为 0 如果为 0 则在最前面加 1 **示例 3**
### 动画描述
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/iejo0.gif)
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/15na7.gif)
### 代码实现
```java
public class Solution {
public int[] plusOne(int[] digits) {
int n = digits.length;
//从数组末尾开始向前遍历
for (int i = digits.length - 1; i >= 0; --i) {
if (digits[i] < 9) {
digits[i]++;
//没有进位直接返回
return digits;
}
//产生进位需要将该位赋值为 0
digits[i] = 0;
}
//整体产生了进位数组长度需要变化加 1
int[] res = new int[n + 1];
res[0] = 1;
return res;
}
}
```
![](../../Pictures/qrcode.jpg)

View File

@ -0,0 +1,75 @@
# LeetCode 75 号问题颜色分类
> 本文首发于公众号图解面试算法 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一
>
> 同步博客https://www.algomooc.com
题目来源于 LeetCode 上第 75 号问题颜色分类题目难度为 Medium目前通过率为 51.8%
### 题目描述
给定一个包含红色白色和蓝色一共 *n* 个元素的数组**原地**对它们进行排序使得相同颜色的元素相邻并按照红色白色蓝色顺序排列
此题中我们使用整数 0 1 2 分别表示红色白色和蓝色
**注意:**
不能使用代码库中的排序函数来解决这道题
**示例:**
```
输入: [2,0,2,1,1,0]
输出: [0,0,1,1,2,2]
```
**进阶**
- 一个直观的解决方案是使用计数排序的两趟扫描算法
首先迭代计算出01 2 元素的个数然后按照012的排序重写当前数组
- 你能想出一个仅使用常数空间的一趟扫描算法吗
### 题目解析
结合三路快排 partition 思路的应用
设定两个索引一个从左往右滑动`zero`一个从右往左滑动`two`
* 遍历`nums``nums[i]`的值为1时`i++`
* `nums[i]`的值为2时`two`的值先减1而后交换`nums[i]``nums[two]`此时在观察`nums[i]`的值
* `nums[i]`的值为0时`zero++`而后交换`nums[i]``nums[zero]``i++`; `i = two`结束循环
### 动画描述
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/6g5tm.gif)
### 代码实现
```
// 三路快速排序的思想
// 对整个数组只遍历了一遍
// 时间复杂度: O(n)
// 空间复杂度: O(1)
class Solution {
public:
void sortColors(vector<int> &nums) {
int zero = -1; // [0...zero] == 0
int two = nums.size(); // [two...n-1] == 2
for(int i = 0 ; i < two ; ){
if(nums[i] == 1){
i ++;
}else if (nums[i] == 2){
two--;
swap( nums[i] , nums[two]);
}else{ // nums[i] == 0
zero++;
swap(nums[zero] , nums[i]);
i++;
}
}
}
};
```
![](../../Pictures/qrcode.jpg)

View File

@ -0,0 +1,71 @@
# LeetCode 86 号问题分割链表
> 本文首发于公众号图解面试算法 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一
>
> 同步博客https://www.algomooc.com
题目来源于 LeetCode 上第 86 号问题分割链表题目难度为 Easy目前通过率为 47.8%
### 题目描述
给定一个链表和一个特定值 *x*对链表进行分隔使得所有小于 *x* 的节点都在大于或等于 *x* 的节点之前
你应当保留两个分区中每个节点的初始相对位置
**示例:**
```
输入: head = 1->4->3->2->5->2, x = 3
输出: 1->2->2->4->3->5
```
### 题目解析
这道题要求我们划分链表把所有小于给定值的节点都移到前面大于该值的节点顺序不变相当于一个局部排序的问题
- 设定两个虚拟节点`dummyHead1 `用来保存小于于该值的链表`dummyHead2 `来保存大于等于该值的链表
- 遍历整个原始链表将小于该值的放于`dummyHead1 `其余的放置在`dummyHead2 `
- 遍历结束后`dummyHead2 `插入到`dummyHead1 `后面
### 动画描述
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/t96zg.gif)
### 代码实现
```
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
ListNode* dummyHead1 = new ListNode(-1);
ListNode* dummyHead2 = new ListNode(-1);
ListNode* prev1 = dummyHead1;
ListNode* prev2 = dummyHead2;
for(ListNode* cur = head ; cur != NULL ;){
if(cur->val < x){
prev1->next = cur;
cur = cur->next;
prev1 = prev1->next;
prev1->next = NULL;
}
else{
prev2->next = cur;
cur = cur->next;
prev2 = prev2->next;
prev2->next = NULL;
}
}
prev1->next = dummyHead2->next;
ListNode* ret = dummyHead1->next;
delete dummyHead1;
delete dummyHead2;
return ret;
}
};
```
![](../../Pictures/qrcode.jpg)

View File

@ -0,0 +1,74 @@
# LeetCode 92 号问题反转链表 II
> 本文首发于公众号图解面试算法 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一
>
> 同步博客https://www.algomooc.com
题目来源于 LeetCode 上第 92 号问题反转链表 II题目难度为 Medium目前通过率为 43.8%
### 题目描述
反转从位置 *m* *n* 的链表请使用一趟扫描完成反转
**说明:**
1 *m* *n* 链表长度
**示例:**
```
输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL
```
### 题目解析
**[Reverse Linked List](https://xiaozhuanlan.com/topic/7513064892)**的延伸题
可以考虑取出需要反转的这一小段链表反转完后再插入到原先的链表中
**以本题为例**
变换的是 234这三个点那么我们可以先取出 2 front 指针指向 2 然后当取出 3 的时候我们把 3 加到 2 的前面 front 指针前移到 3 依次类推 4 后停止这样我们得到一个新链表 4 -> 3 -> 2 , front 指针指向4
对于原链表来说**有两个点的位置很重要**需要用指针记录下来分别是 1 5 把新链表插入的时候需要这两个点的位置
- pre 指针记录 1 的位置
- 4 结点被取走后5 的位置需要记下来
- 这样我们就可以把倒置后的那一小段链表加入到原链表中
### 动画描述
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/rjjr0.gif)
### 代码实现
```
class Solution {
public:
ListNode *reverseBetween(ListNode *head, int m, int n) {
ListNode *dummy = new ListNode(-1);
dummy->next = head;
ListNode *cur = dummy;
ListNode *pre, *front, *last;
for (int i = 1; i <= m - 1; ++i) cur = cur->next;
pre = cur;
last = cur->next;
for (int i = m; i <= n; ++i) {
cur = pre->next;
pre->next = cur->next;
cur->next = front;
front = cur;
}
cur = pre->next;
pre->next = front;
last->next = cur;
return dummy->next;
}
};
```
![](../../Pictures/qrcode.jpg)

View File

@ -0,0 +1,67 @@
# LeetCode 94 号问题二叉树的中序遍历
> 本文首发于公众号图解面试算法 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一
>
> 同步博客https://www.algomooc.com
题目来源于 LeetCode 上第 94 号问题二叉树的中序遍历题目难度为 Medium目前通过率为 35.8%
### 题目描述
给定一个二叉树返回它的*中序* 遍历
**示例:**
```
输入: [1,null,2,3]
1
\
2
/
3
输出: [1,3,2]
```
**进阶:** 递归算法很简单你可以通过迭代算法完成吗
### 题目解析
**(Stack)**的思路来处理问题
中序遍历的顺序为**--**具体算法为
- 从根节点开始先将根节点压入栈
- 然后再将其所有左子结点压入栈取出栈顶节点保存节点值
- 再将当前指针移到其右子节点上若存在右子节点则在下次循环时又可将其所有左子结点压入栈中
### 动画描述
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/v17b8.gif)
### 代码实现
```
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
while (cur != null || !stack.isEmpty()) {
if (cur != null) {
stack.push(cur);
cur = cur.left;
} else {
cur = stack.pop();
list.add(cur.val);
cur = cur.right;
}
}
return list;
}
}
```
![](../../Pictures/qrcode.jpg)

View File

@ -0,0 +1,48 @@
# LeetCode 101 号问题对称二叉树
> 本文首发于公众号图解面试算法 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一
>
> 同步博客https://www.algomooc.com
题目来源于 LeetCode 101 号问题对称二叉树
### 题目描述
给定一个二叉树检查它是否是镜像对称的
例如二叉树 `[1,2,2,3,4,4,3]` 是对称的
```
1
/ \
2 2
/ \ / \
3 4 4 3
```
### 题目解析
用递归做比较简单一棵树是对称的**等价**于它的左子树和右子树两棵树是对称的问题就转变为判断两棵树是否对称
### 代码实现
```java
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root == null) return true;
//把问题变成判断两棵树是否是对称的
return isSym(root.left, root.right);
}
//判断的是根节点为r1和r2的两棵树是否是对称的
public boolean isSym(TreeNode r1, TreeNode r2){
if(r1 == null && r2 == null) return true;
if(r1 == null || r2 == null) return false;
//这两棵树是对称需要满足的条件
//1.俩根节点相等 2.树1的左子树和树2的右子树树2的左子树和树1的右子树都得是对称的
return r1.val == r2.val && isSym(r1.left, r2.right)
&& isSym(r1.right, r2.left);
}
}
```
![](../../Pictures/qrcode.jpg)

View File

@ -0,0 +1,97 @@
# LeetCode 102 号问题二叉树的层序遍历
> 本文首发于公众号图解面试算法 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一
>
> 同步博客https://www.algomooc.com
题目来源于 LeetCode 上第 102 号问题二叉树的层序遍历题目难度为 Medium目前通过率为 55.8%
### 题目描述
给定一个二叉树返回其按层次遍历的节点值 即逐层地从左到右访问所有节点
例如:
给定二叉树: `[3,9,20,null,null,15,7]`,
```
3
/ \
9 20
/ \
15 7
```
返回其层次遍历结果
```
[
[3],
[9,20],
[15,7]
]
```
### 题目解析
该问题需要用到**队列**
- 建立一个queue
- 先把根节点放进去这时候找根节点的左右两个子节点
- 去掉根节点此时queue里的元素就是下一层的所有节点
- 用for循环遍历将结果存到一个一维向量里
- 遍历完之后再把这个一维向量存到二维向量里
- 以此类推可以完成层序遍历
### 动画描述
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/2elr5.gif)
### 代码实现
```
/// BFS
/// Time Complexity: O(n), where n is the number of nodes in the tree
/// Space Complexity: O(n)
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> res;
if(root == NULL)
return res;
queue<pair<TreeNode*,int>> q;
q.push(make_pair(root, 0));
while(!q.empty()){
TreeNode* node = q.front().first;
int level = q.front().second;
q.pop();
if(level == res.size())
res.push_back(vector<int>());
assert( level < res.size() );
res[level].push_back(node->val);
if(node->left)
q.push(make_pair(node->left, level + 1 ));
if(node->right)
q.push(make_pair(node->right, level + 1 ));
}
return res;
}
};
```
![](../../Pictures/qrcode.jpg)

View File

@ -0,0 +1,56 @@
# LeetCode 103 号问题二叉树的锯齿形层次遍历
> 本文首发于公众号图解面试算法 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一
>
> 同步博客https://www.algomooc.com
题目来源于 LeetCode 上第 103 号问题二叉树的锯齿形层次遍历题目难度为 Medium目前通过率为 43.8%
### 题目描述
给定一个二叉树返回其节点值的锯齿形层次遍历即先从左往右再从右往左进行下一层遍历以此类推层与层之间交替进行
例如
给定二叉树 `[3,9,20,null,null,15,7]`,
```
3
/ \
9 20
/ \
15 7
```
返回锯齿形层次遍历如下
```
[
[3],
[20,9],
[15,7]
]
```
### 题目解析
该问题需要用到**队列**与之前的[二叉树的层次遍历](https://xiaozhuanlan.com/topic/8579460312)类似不同点在于在偶数层需要翻转一下
- 建立一个queue
- 先把根节点放进去这时候找根节点的左右两个子节点
- 去掉根节点此时queue里的元素就是下一层的所有节点
- 循环遍历将结果存到一个一维向量里
- 遍历完之后再把这个一维向量存到二维向量里
- 如果该层为偶数层则reverse翻转一下
- 以此类推可以完成层序遍历
### 动画描述
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/xuoqo.gif)
### 代码实现
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/7mnmj.png)
![](../../Pictures/qrcode.jpg)

View File

@ -0,0 +1,59 @@
# LeetCode 107 号问题二叉树的层次遍历 II
> 本文首发于公众号图解面试算法 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一
>
> 同步博客https://www.algomooc.com
题目来源于 LeetCode 上第 107 号问题二叉树的层次遍历 II题目难度为 Easy目前通过率为 55.8%
### 题目描述
给定一个二叉树返回其节点值自底向上的层次遍历 即按从叶子节点所在层到根节点所在的层逐层从左向右遍历
例如
给定二叉树 `[3,9,20,null,null,15,7]`,
```
3
/ \
9 20
/ \
15 7
```
返回其自底向上的层次遍历为
```
[
[15,7],
[9,20],
[3]
]
```
### 题目解析
该问题需要用到**队列**解法与上篇[每天一算Binary Tree Level Order Traversal](https://xiaozhuanlan.com/topic/8579460312)类似区别在于最后存储方式的不同
- 建立一个 queue
- 先把根节点放进去这时候找根节点的左右两个子节点
- 去掉根节点此时queue里的元素就是下一层的所有节点
- for 循环遍历将结果存到一个一维向量里
- 遍历完之后再把这个一维向量**插入**到二维向量里
- 以此类推可以完成层序遍历
### 动画描述
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/varp8.gif)
### 代码实现
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/9iccc.png)
![](../../Pictures/qrcode.jpg)

View File

@ -0,0 +1,47 @@
# LeetCode 110 号问题平衡二叉树
> 本文首发于公众号图解面试算法 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一
>
> 同步博客https://www.algomooc.com
题目来源于 LeetCode 上第 110 号问题平衡二叉树
### 题目描述
给定一个二叉树判断它是否是高度平衡的二叉树
### 题目解析
采取**后序遍历**的方式遍历二叉树的每一个结点
在遍历到一个结点之前已经遍历了它的左右子树那么只要在遍历每个结点的时候记录它的深度某一结点的深度等于它到叶结点的路径的长度就可以一边遍历一边判断每个结点是不是平衡的
### 动画描述
待补充
### 代码实现
```java
class Solution {
private boolean isBalanced = true;
public boolean isBalanced(TreeNode root) {
getDepth(root);
return isBalanced;
}
public int getDepth(TreeNode root) {
if (root == null)
return 0;
int left = getDepth(root.left);
int right = getDepth(root.right);
if (Math.abs(left - right) > 1) {
isBalanced = false;
}
return right > left ? right + 1 : left + 1;
}
}
```
![](../../Pictures/qrcode.jpg)

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

View File

@ -0,0 +1,78 @@
# LeetCode 125 号问题验证回文串
> 本文首发于公众号图解面试算法 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一
>
> 同步博客https://www.algomooc.com
题目来源于 LeetCode 125 号问题验证回文串这道题目是 **初级程序员** 在面试的时候经常遇到的一道算法题而且面试官喜欢面试者手写
### 题目描述
给定一个字符串验证它是否是回文串只考虑字母和数字字符可以忽略字母的大小写
**说明**本题中我们将空字符串定义为有效的回文串
**示例 1:**
```
输入: "A man, a plan, a canal: Panama"
输出: true
```
**示例 2:**
```
输入: "race a car"
输出: false
```
### 题目解析
先理解一个概念所谓回文就是一个正读和反读都一样的字符串
先假设是验证单词 `level` 是否是回文字符串通过概念涉及到 那么很容易想到使用双指针从字符的开头和结尾处开始遍历整个字符串相同则继续向前寻找不同则直接返回 false
而这里与单独验证一个单词是否是回文字符串有所区别的是加入了 空格 非字母数字的字符但实际上的做法一样的
一开始先建立两个指针left right , 让它们分别从字符的开头和结尾处开始遍历整个字符串
如果遇到非字母数字的字符就跳过继续往下找直到找到下一个字母数字或者结束遍历如果遇到大写字母就将其转为小写
当左右指针都找到字母数字时可以进行比较的时候比较这两个字符如果相等则两个指针向它们的前进方向挪动然后继续比较下面两个分别找到的字母数字若不相等直接返回 false
### 动画描述
![](../Animation/animation.gif)
### 代码实现
`isLetterOrDigit ` 方法确定指定的字符是否为字母或数字
```java
class Solution {
public boolean isPalindrome(String s) {
if(s.length() == 0)
return true;
int l = 0, r = s.length() - 1;
while(l < r){
//确定指定的字符是否为字母或数字
if(!Character.isLetterOrDigit(s.charAt(l))){
l++;
}else if(!Character.isLetterOrDigit(s.charAt(r))){
r--;
}else{
if(Character.toLowerCase(s.charAt(l)) != Character.toLowerCase(s.charAt(r)))
return false;
l++;
r--;
}
}
return true;
}
}
```
![](../../Pictures/qrcode.jpg)

BIN
Pictures/qrcode.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

View File

@ -8,9 +8,13 @@
我会尽力将 LeetCode 上所有的题目都用动画的形式演示出来计划用 3 4 年时间去完成它期待与你见证这一天
文章最新首发于微信公众号 **五分钟学算法** 您可以关注获取最新的文章
文章最新首发于微信公众号 **图解面试算法**您可以关注获取最新的文章
我已经将所有文章同步到了我的个人博客如果国内访问 GitHub 较慢图片裂开可以访问这个地址[https://www.cxyxiaowu.com/likou/leetcode](https://www.cxyxiaowu.com/likou/leetcode)
![](Pictures/qrcode.jpg)
文章同步博客地址https://www.algomooc.com
## 汇总
@ -75,7 +79,7 @@
| 219 | [存在重复元素 II](https://github.com/MisterBooo/LeetCodeAnimation/tree/master/notes/LeetCode第219号问题存在重复元素II.md) | |
| 229 | [求众数II](https://mp.weixin.qq.com/s/ObO4eQbjp1s1g_WXPkjixQ) | |
| 231 | [2的幂](https://github.com/MisterBooo/LeetCodeAnimation/tree/master/notes/LeetCode第231号问题2的幂.md) | |
| 232 | [使用栈实现队列](https://mp.weixin.qq.com/s/j6w94_PjvsL9Dip_xBcqcg) | |
| 232 | [使用栈实现队列](https://mp.weixin.qq.com/s/j6w94_PjvsL9Dip_xBcqcg) | |
| 237 | [删除链表中的节点](https://mp.weixin.qq.com/s/2XdUeDNblryFpXpTUgsaMQ) | |
| 239 | [滑动窗口最大值](https://github.com/MisterBooo/LeetCodeAnimation/tree/master/notes/LeetCode第239号问题滑动窗口最大值.md) | |
| 242 | [有效的字母异位词](https://mp.weixin.qq.com/s/o5HTxmOgpftSaQdebS9zyQ) | |
@ -102,27 +106,10 @@
| 1025 | [除数博弈](https://mp.weixin.qq.com/s/0u6z02QYj1OpAwf54k8-Dw) | |
| 1099 | [小于 K 的两数之和](https://mp.weixin.qq.com/s/S6BbLeP_th_9JheNX7NN-w) | |
## 几篇学习算法的经验贴
[六千字干货文到底要怎么去学算法](https://mp.weixin.qq.com/s/7cpixzxE2DLaEn7F615AqQ)
[微信大佬总结的算法学习经验](https://mp.weixin.qq.com/s/fECqsr3T4WKNcx7s-2ozuA)
邮箱leetcodeanimation@qq.com
喜欢就 star 一下吧
## 和我交流
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/6nqpz.jpeg)
![](Pictures/qrcode.jpg)