Commit f1048508 authored by 程序员吴师兄's avatar 程序员吴师兄
Browse files

整理文件

parent c3aa5c59
# LeetCode 第 279 号问题:完全平方数
> 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一。
>
> 同步博客:https://www.algomooc.com
题目来源于 LeetCode 上第 279 号问题:完全平方数。题目难度为 Medium,目前通过率为 49.1% 。
### 题目描述
给定正整数 *n*,找到若干个完全平方数(比如 `1, 4, 9, 16, ...`)使得它们的和等于 *n*。你需要让组成和的完全平方数的个数最少。
**示例 1:**
```
输入: n = 12
输出: 3
解释: 12 = 4 + 4 + 4.
```
**示例 2:**
```
输入: n = 13
输出: 2
解释: 13 = 4 + 9.
```
### 题目解析
这道题目很有意思。
大部分文章给出的答案都是依托于一个定理:**四平方定理**
四平方定理讲的就是任何一个正整数都可以表示成不超过四个整数的平方之和。也就是说,这道题的答案只有 1,2 ,3,4 这四种可能。
同时,还有一个非常重要的推论满足四数平方和定理的数n(这里要满足由四个数构成,小于四个不行),必定满足 n = 4<sup>a</sup> * (8b + 7)。
根据这个重要的推论来解决此题,首先将输入的`n`迅速缩小。然后再判断,这个缩小后的数是否可以通过`两个平方数的和或一个平方数`组成,不能的话我们返回`3`,能的话我们返回`平方数的个数`
所以代码很简洁,如下:
```java
public int numSquares(int n) {
while (n % 4 == 0){
n /= 4;
}
if ( n % 8 == 7){
return 4;
}
int a = 0;
while ( (a * a) <= n){
int b = (int)Math.pow((n - a * a),0.5);
if(a * a + b * b == n) {
//如果可以 在这里返回
if(a != 0 && b != 0) {
return 2;
} else{
return 1;
}
}
a++;
}
return 3;
}
```
但因为本章是「广度优先遍历」的专栏,因此再补充一个图的广度优先遍历的答案:
使用广度优先搜索方法,将 n 依次减去比 n 小的所有平方数,直至 n = 0 ,此时的层数即为最后的结果。
### 动画描述
![](../Animation/Animation.gif)
### 代码实现
```
import java.util.LinkedList;
import javafx.util.Pair;
class Solution {
public int numSquares(int n) {
if(n == 0)
return 0;
LinkedList<Pair<Integer, Integer>> queue = new LinkedList<Pair<Integer, Integer>>();
queue.addLast(new Pair<Integer, Integer>(n, 0));
boolean[] visited = new boolean[n+1];
visited[n] = true;
while(!queue.isEmpty()){
Pair<Integer, Integer> front = queue.removeFirst();
int num = front.getKey();
int step = front.getValue();
if(num == 0)
return step;
for(int i = 1 ; num - i*i >= 0 ; i ++){
int a = num - i*i;
if(!visited[a]){
if(a == 0) return step + 1;
queue.addLast(new Pair(num - i * i, step + 1));
visited[num - i * i] = true;
}
}
}
return 0;
}
}
```
![](../../Pictures/qrcode.jpg)
# LeetCode 第 283 号问题:移动零
> 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一。
>
> 同步博客:https://www.algomooc.com
题目来源于 LeetCode 上第 283 号问题:移动零。题目难度为 Easy,目前通过率为 53.8% 。
### 题目描述
给定一个数组 `nums`,编写一个函数将所有 `0` 移动到数组的末尾,同时保持非零元素的相对顺序。
**示例:**
```
输入: [0,1,0,3,12]
输出: [1,3,12,0,0]
```
**说明**:
1. 必须在原数组上操作,不能拷贝额外的数组。
2. 尽量减少操作次数。
### 题目解析
设定一个临时变量 k = 0,遍历数组 nums ,将非零元素移动到 nums[k]位 置,同时 k++,而后将【k,….nums.size()】中的元素置零。
### 解法一
创建一个临时数组 nonZeroElements ,遍历 nums ,将 nums 中非 0 元素赋值到 nonZeroElements中,而后按顺序将 nonZeroElements 赋值到 nums 上,未遍历的元素置 0 ;
动画如下:
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/0eeix.gif)
代码如下:
```
// 时间复杂度: O(n)
// 空间复杂度: O(n)
class Solution {
public:
void moveZeroes(vector<int>& nums) {
vector<int> nonZeroElements;
// 将vec中所有非0元素放入nonZeroElements中
for(int i = 0 ; i < nums.size() ; i ++)
if(nums[i])
nonZeroElements.push_back(nums[i]);
// 将nonZeroElements中的所有元素依次放入到nums开始的位置
for(int i = 0 ; i < nonZeroElements.size() ; i ++)
nums[i] = nonZeroElements[i];
// 将nums剩余的位置放置为0
for(int i = nonZeroElements.size() ; i < nums.size() ; i ++)
nums[i] = 0;
}
};
```
### 解法二
设定一个临时变量 k = 0,遍历数组 nums ,将非零元素移动到 nums[k] 位置,同时 k++,而后将【k,….nums.size()】中的元素置零。
动画如下:
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/jodp0.gif)
代码如下:
```
// 原地(in place)解决该问题
// 时间复杂度: O(n)
// 空间复杂度: O(1)
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int k = 0; // nums中, [0...k)的元素均为非0元素
// 遍历到第i个元素后,保证[0...i]中所有非0元素
// 都按照顺序排列在[0...k)中
for(int i = 0 ; i < nums.size() ; i ++)
if(nums[i])
nums[k++] = nums[i];
// 将nums剩余的位置放置为0
for(int i = k ; i < nums.size() ; i ++)
nums[i] = 0;
}
};
```
### 解法三
思路:设定一个临时变量 k = 0,遍历数组 nums,将非零元素与之前的零元素进行交换,维护变量k的值。
动画如下:
![](../Animation/Animation.gif)
代码如下:
```
// 原地(in place)解决该问题
// 时间复杂度: O(n)
// 空间复杂度: O(1)
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int k = 0; // nums中, [0...k)的元素均为非0元素
// 遍历到第i个元素后,保证[0...i]中所有非0元素
// 都按照顺序排列在[0...k)中
// 同时, [k...i] 为 0
for(int i = 0 ; i < nums.size() ; i ++)
if(nums[i]){
if(k != i){
swap(nums[k++] , nums[i]);
}else{
k ++;
}
}
}
};
```
![](../../Pictures/qrcode.jpg)
# LeetCode 第 295 号问题:数据流的中位数
> 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一。
>
> 同步博客:https://www.algomooc.com
题目来源于 LeetCode 上第 295 号问题:数据流的中位数。难度级别为 Hard,目前通过率为 33.5% 。
### 题目描述
中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。
例如,
[2,3,4] 的中位数是 3
[2,3] 的中位数是 (2 + 3) / 2 = 2.5
设计一个支持以下两种操作的数据结构:
- void addNum(int num) - 从数据流中添加一个整数到数据结构中。
- double findMedian() - 返回目前所有元素的中位数。
**示例:**
```java
addNum(1)
addNum(2)
findMedian() -> 1.5
addNum(3)
findMedian() -> 2
```
### 题目解析
这道题给我们一个数据流,让我们找出中位数。对于数据流这种动态(流动)的数据,如果使用数组存储,那么每次新进来一个数据都进行排序的话,效率很低。
处理动态数据来说一般使用的数据结构是栈、队列、二叉树、堆。
本题中,我们使用 **堆** 这种数据结构。
首先将数据分为两部分,位于 **上边最大堆** 的数据要比 **下边最小堆** 的数据都要小。
为了保证将数据平均分配到两个堆中,在动态的操作的过程中两个堆中数据的数目之差不能超过 1。
为了保证 **最大堆中的所有数据都小于最小堆中的数据**,在操作过程中,新添加进去的数据需要先和最大堆的最大值或者最小堆中的最小值进行比较。
### 动画描述
![](../Animation/Animation.gif)
### 代码实现
```java
class MedianFinder {
public PriorityQueue<Integer> minheap, maxheap;
public MedianFinder() {
//维护较大的元素的最小堆
maxheap = new PriorityQueue<Integer>(Collections.reverseOrder());
//维护较小元素的最大堆
minheap = new PriorityQueue<Integer>();
}
// Adds a number into the data structure.
public void addNum(int num) {
maxheap.add(num);
minheap.add(maxheap.poll());
if (maxheap.size() < minheap.size()) {
maxheap.add(minheap.poll());
}
}
// Returns the median of current data stream
public double findMedian() {
if (maxheap.size() == minheap.size()) {
return (maxheap.peek() + minheap.peek()) * 0.5;
} else {
return maxheap.peek();
}
}
};
```
![](../../Pictures/qrcode.jpg)
\ No newline at end of file
# LeetCode 第 328 号问题:奇偶链表
> 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一。
>
> 同步博客:https://www.algomooc.com
题目来源于 LeetCode 上第 328 号问题:奇偶链表。题目难度为 Medium,目前通过率为 52.0% 。
### 题目描述
给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。
请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。
**示例 1:**
```
输入: 1->2->3->4->5->NULL
输出: 1->3->5->2->4->NULL
```
**示例 2:**
```
输入: 2->1->3->5->6->4->7->NULL
输出: 2->3->6->7->1->5->4->NULL
```
**说明:**
- 应当保持奇数节点和偶数节点的相对顺序。
- 链表的第一个节点视为奇数节点,第二个节点视为偶数节点,以此类推。
### 题目解析
这道题给了我们一个链表,让我们分开奇偶节点,所有奇节点在前,偶节点在后。
* 设定两个虚拟节点,`dummyHead1 `用来保存奇节点,`dummyHead2 `来保存偶节点;
* 遍历整个原始链表,将奇节点放于`dummyHead1 `中,其余的放置在`dummyHead2 `
* 遍历结束后,将`dummyHead2 `插入到`dummyHead1 `后面
### 动画描述
![](../Animation/Animation.gif)
### 代码实现
```
class Solution {
public:
ListNode* oddEvenList(ListNode* head) {
if(head == NULL || head->next == NULL || head->next->next == NULL)
return head;
ListNode* dummyHead1 = new ListNode(-1);
ListNode* dummyHead2 = new ListNode(-1);
ListNode* p1 = dummyHead1;
ListNode* p2 = dummyHead2;
ListNode* p = head;
for(int i = 0; p; i ++)
if(i % 2 == 0){
p1->next = p;
p = p->next;
p1 = p1->next;
p1->next = NULL;
}
else{
p2->next = p;
p = p->next;
p2 = p2->next;
p2->next = NULL;
}
p1->next = dummyHead2->next;
ListNode* ret = dummyHead1->next;
delete dummyHead1;
delete dummyHead2;
return ret;
}
};
```
![](../../Pictures/qrcode.jpg)
# LeetCode 第 342 号问题:4 的幂
> 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一。
>
> 同步博客:https://www.algomooc.com
题目来源于 LeetCode 上第 342 号问题:4 的幂。题目难度为 Easy,目前通过率为 45.3% 。
### 题目描述
给定一个整数 (32 位有符号整数),请编写一个函数来判断它是否是 4 的幂次方。
**示例 1:**
```
输入: 16
输出: true
```
**示例 2:**
```
输入: 5
输出: false
```
**进阶:**
你能不使用循环或者递归来完成本题吗?
### 题目解析
这道题最直接的方法就是不停的去除以 4 ,看最终结果是否为 1 ,参见代码如下:
```java
class Solution {
public boolean isPowerOfFour(int num) {
while ( (num != 0) && (num % 4 == 0)) {
num /= 4;
}
return num == 1;
}
}
```
不过这段代码使用了 **循环** ,逼格不够高。
对于一个整数而言,如果这个数是 4 的幂次方,那它必定也是 2 的幂次方。
我们先将 2 的幂次方列出来找一下其中哪些数是 4 的幂次方。
| 十进制 | 二进制 |
| ------ | ------------------------------- |
| 2 | 10 |
| 4 | **100** (1 在第 3 位) |
| 8 | 1000 |
| 16 | **10000**(1 在第 5 位) |
| 32 | 100000 |
| 64 | **1000000**(1 在第 7 位) |
| 128 | 10000000 |
| 256 | **100000000**(1 在第 9 位) |
| 512 | 1000000000 |
| 1024 | **10000000000**(1 在第 11 位) |
找一下规律: 4 的幂次方的数的二进制表示 1 的位置都是在**奇数位**
之前在小吴的文章中判断一个是是否是 2 的幂次方数使用的是位运算 `n & ( n - 1 )`。同样的,这里依旧可以使用位运算:将这个数与特殊的数做位运算。
这个特殊的数有如下特点:
* 足够大,但不能超过 32 位,即最大为 1111111111111111111111111111111( 31 个 1)
* 它的二进制表示中奇数位为 1 ,偶数位为 0
符合这两个条件的二进制数是:
```java
1010101010101010101010101010101
```
**如果用一个 4 的幂次方数和它做与运算,得到的还是 4 的幂次方数**
将这个二进制数转换成 16 进制表示:0x55555555 。有没有感觉逼格更高点。。。
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/c0s9n.png)
### 图片描述
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/ux5pa.jpg)
### 代码实现
```java
class Solution {
public boolean isPowerOfFour(int num) {
if (num <= 0)
return false;
//先判断是否是 2 的幂
if ((num & num - 1) != 0)
return false;
//如果与运算之后是本身则是 4 的幂
if ((num & 0x55555555) == num)
return true;
return false;
}
}
```
![](../../Pictures/qrcode.jpg)
\ No newline at end of file
# LeetCode 第 344 号问题:反转字符串
> 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一。
>
> 同步博客:https://www.algomooc.com
题目来源于 LeetCode 第 344 号问题:反转字符串。面试官最喜欢让你手写的一道算法题!
### 题目描述
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 `char[]` 的形式给出。
不要给另外的数组分配额外的空间,你必须**原地修改输入数组**、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 [ASCII](https://baike.baidu.com/item/ASCII) 码表中的可打印字符。
**示例 1:**
```
输入:["h","e","l","l","o"]
输出:["o","l","l","e","h"]
```
**示例 2:**
```
输入:["H","a","n","n","a","h"]
输出:["h","a","n","n","a","H"]
```
### 题目解析
这道题没什么难度,直接从两头往中间走,同时交换两边的字符。注意需要白板编程写出来即可,也注意千万别回答一句使用 reverse() 这种高级函数来解决。。。
### 动画描述
![](../Animation/Animation.gif)
### 代码实现
```
class Solution {
public:
string reverseString(string s) {
int i = 0, j = s.size() - 1;
while (i < j){
swap(s[i],s[j]);
i++;
j--;
}
return s;
}
};
```
![](../../Pictures/qrcode.jpg)
# LeetCode 第 347 号问题:前 K 个高频元素
> 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一。
>
> 同步博客:https://www.algomooc.com
今天分享的题目来源于 LeetCode 上第 347 号问题:前 K 个高频元素。题目难度为 Medium,目前通过率为 56.9% 。
## 题目描述
给定一个非空的整数数组,**返回其中出现频率前 k 高**的元素。
**示例 1:**
```
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
```
**示例 2:**
```
输入: nums = [1], k = 1
输出: [1]
```
**说明:**
- 你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
- 你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。
### 题目解析
### 解法一:粗暴排序法
最简单粗暴的思路就是 **使用排序算法对元素按照频率由高到低进行排序**,然后再取前 k 个元素。
以下十种排序算法,任你挑选!
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/qya5e.png)
可以发现,使用常规的诸如 冒泡、选择、甚至快速排序都是不满足题目要求,它们的时间复杂度都是大于或者等于 O(n log⁡n) ,而题目要求算法的时间复杂度必须优于 O(n log n) 。
#### 复杂度分析
- **时间复杂度**:O(nlogn),n 表示数组长度。首先,遍历一遍数组统计元素的频率,这一系列操作的时间复杂度是 O(n);接着,排序算法时间复杂度为O(nlogn) ;因此整体时间复杂度为 O(nlogn) 。
- **空间复杂度**:O(n),最极端的情况下(每个元素都不同),用于存储元素及其频率的 Map 需要存储 n 个键值对。
### 解法二:最小堆
题目最终需要返回的是前 k 个频率最大的元素,可以想到借助堆这种数据结构,对于 k 频率之后的元素不用再去处理,进一步优化时间复杂度。
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/nloow.jpg)
具体操作为:
- 借助 **哈希表** 来建立数字和其出现次数的映射,遍历一遍数组统计元素的频率
- 维护一个元素数目为 k 的最小堆
- 每次都将新的元素与堆顶元素(堆中频率最小的元素)进行比较
- 如果新的元素的频率比堆顶端的元素大,则弹出堆顶端的元素,将新的元素添加进堆中
- 最终,堆中的 k 个元素即为前 k 个高频元素
### 动画理解
![](../Animation/Animation.gif)
### 参考代码
```java
class Solution {
public List<Integer> topKFrequent(int[] nums, int k) {
// 使用字典,统计每个元素出现的次数,元素为键,元素出现的次数为值
HashMap<Integer,Integer> map = new HashMap();
for(int num : nums){
if (map.containsKey(num)) {
map.put(num, map.get(num) + 1);
} else {
map.put(num, 1);
}
}
// 遍历map,用最小堆保存频率最大的k个元素
PriorityQueue<Integer> pq = new PriorityQueue<>(new Comparator<Integer>() {
@Override
public int compare(Integer a, Integer b) {
return map.get(a) - map.get(b);
}
});
for (Integer key : map.keySet()) {
if (pq.size() < k) {
pq.add(key);
} else if (map.get(key) > map.get(pq.peek())) {
pq.remove();
pq.add(key);
}
}
// 取出最小堆中的元素
List<Integer> res = new ArrayList<>();
while (!pq.isEmpty()) {
res.add(pq.remove());
}
return res;
}
}
```
#### 复杂度分析
- **时间复杂度**:O(nlogk), n 表示数组的长度。首先,遍历一遍数组统计元素的频率,这一系列操作的时间复杂度是 O(n);接着,遍历用于存储元素频率的 map,如果元素的频率大于最小堆中顶部的元素,则将顶部的元素删除并将该元素加入堆中,**这里维护堆的数目是 k **,所以这一系列操作的时间复杂度是 O(nlogk)的;因此,总的时间复杂度是 O(nlog⁡k) 。
- **空间复杂度**:O(n),最坏情况下(每个元素都不同),map 需要存储 n 个键值对,优先队列需要存储 k个元素,因此,空间复杂度是 O(n)。
### 解法三:桶排序法
首先依旧使用哈希表统计频率,统计完成后,创建一个数组,将频率作为数组下标,对于出现频率不同的数字集合,存入对应的数组下标即可。
![](https://blog-1257126549.cos.ap-guangzhou.myqcloud.com/blog/6tge2.jpg)
代码实现如下:
```java
//基于桶排序求解「前 K 个高频元素」
class Solution {
public List<Integer> topKFrequent(int[] nums, int k) {
List<Integer> res = new ArrayList();
// 使用字典,统计每个元素出现的次数,元素为键,元素出现的次数为值
HashMap<Integer,Integer> map = new HashMap();
for(int num : nums){
if (map.containsKey(num)) {
map.put(num, map.get(num) + 1);
} else {
map.put(num, 1);
}
}
//桶排序
//将频率作为数组下标,对于出现频率不同的数字集合,存入对应的数组下标
List<Integer>[] list = new List[nums.length+1];
for(int key : map.keySet()){
// 获取出现的次数作为下标
int i = map.get(key);
if(list[i] == null){
list[i] = new ArrayList();
}
list[i].add(key);
}
// 倒序遍历数组获取出现顺序从大到小的排列
for(int i = list.length - 1;i >= 0 && res.size() < k;i--){
if(list[i] == null) continue;
res.addAll(list[i]);
}
return res;
}
}
```
#### 复杂度分析
- **时间复杂度**:O(n), n 表示数组的长度。首先,遍历一遍数组统计元素的频率,这一系列操作的时间复杂度是 O(n);桶的数量为 n + 1,所以桶排序的时间复杂度为 O(n);因此,总的时间复杂度是 O(n)。
- **空间复杂度**:很明显为 O(n)
![](../../Pictures/qrcode.jpg)
# LeetCode 第 349 号问题:两个数组的交集
> 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一。
>
> 同步博客:https://www.algomooc.com
题目来源于 LeetCode 上第 349 号问题:两个数组的交集。题目难度为 Easy,目前通过率为 62.3% 。
### 题目描述
给定两个数组,编写一个函数来计算它们的交集。
**示例 1:**
```
输入: nums1 = [1,2,2,1], nums2 = [2,2]
输出: [2]
```
**示例 2:**
```
输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出: [9,4]
```
**说明:**
- 输出结果中的每个元素一定是唯一的。
- 我们可以不考虑输出结果的顺序。
### 题目解析
容器类 [set](https://zh.cppreference.com/w/cpp/container/set) 的使用。
- 遍历 num1,通过 set 容器 record 存储 num1 的元素
- 遍历 num2 ,在 record 中查找是否有相同的元素,如果有,用 set 容器 resultSet 进行存储
- 将 resultSet 转换为 vector 类型
### 动画描述
![](../Animation/Animation.gif)
### 代码实现
```
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
set<int> record;
for(int i = 0; i < nums1.size(); i ++){
record.insert(nums1[i]);
}
set<int> resultSet;
for(int i = 0; i < nums2.size();i++){
if(record.find(nums2[i]) != record.end()){
resultSet.insert(nums2[i]);
}
}
vector<int> resultVector;
for(set<int>::iterator iter=resultSet.begin(); iter != resultSet.end();iter++){
resultVector.push_back(*iter);
}
return resultVector;
}
};
```
![](../../Pictures/qrcode.jpg)
# LeetCode 第 350 号问题:两个数组的交集 II
> 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一。
>
> 同步博客:https://www.algomooc.com
题目来源于 LeetCode 上第 350 号问题:两个数组的交集 II。题目难度为 Easy,目前通过率为 41.8% 。
### 题目描述
给定两个数组,编写一个函数来计算它们的交集。
**示例 1:**
```
输入: nums1 = [1,2,2,1], nums2 = [2,2]
输出: [2,2]
```
**示例 2:**
```
输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出: [4,9]
```
**说明:**
- 输出结果中每个元素出现的次数,应与元素在两个数组中出现的次数一致。
- 我们可以不考虑输出结果的顺序。
**进阶:**
- 如果给定的数组已经排好序呢?你将如何优化你的算法?
- 如果 *nums1* 的大小比 *nums2* 小很多,哪种方法更优?
- 如果 *nums2* 的元素存储在磁盘上,磁盘内存是有限的,并且你不能一次加载所有的元素到内存中,你该怎么办?
### 题目解析
容器类 [map](https://zh.cppreference.com/w/cpp/container/map) 的使用。
- 遍历 num1,通过map容器 record 存储 num1 的元素与频率
- 遍历 num2 ,在 record 中查找是否有相同的元素(该元素的存储频率大于0),如果有,用map容器resultVector 进行存储,同时该元素的频率减一
### 动画描述
![](../Animation/Animation.gif)
### 代码实现
```
// 350. Intersection of Two Arrays II
// https://leetcode.com/problems/intersection-of-two-arrays-ii/description/
// 时间复杂度: O(nlogn)
// 空间复杂度: O(n)
class Solution {
public:
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
map<int, int> record;
for(int i = 0 ; i < nums1.size() ; i ++){
record[nums1[i]] += 1;
}
vector<int> resultVector;
for(int i = 0 ; i < nums2.size() ; i ++){
if(record[nums2[i]] > 0){
resultVector.push_back(nums2[i]);
record[nums2[i]] --;
}
}
return resultVector;
}
};
```
![](../../Pictures/qrcode.jpg)
# LeetCode 第 445 号问题:两数相加 II
> 本文首发于公众号「图解面试算法」,是 [图解 LeetCode ](<https://github.com/MisterBooo/LeetCodeAnimation>) 系列文章之一。
>
> 同步博客:https://www.algomooc.com
题目来源于 LeetCode 上第 445 号问题:两数相加 II。题目难度为 Medium,目前通过率为 48.8% 。
### 题目描述
给定两个**非空**链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储单个数字。将这两数相加会返回一个新的链表。
你可以假设除了数字 0 之外,这两个数字都不会以零开头。
**进阶:**
如果输入链表不能修改该如何处理?换句话说,你不能对列表中的节点进行翻转。
**示例:**
```
输入: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
输出: 7 -> 8 -> 0 -> 7
```
### 题目解析
由于计算时要保证最右边的数对齐,那么很自然的想到先用**栈**存放链表中的每个值,然后依次计算。由于相加时可能产生进位,所以使用一个flag表示是否有进位。
提示:若栈中元素相加结束之后仍有进位,则需要新加入一个头结点。
### 动画描述
![](../Animation/Animation.gif)
### 代码实现
```python
class Solution:
def addTwoNumbers(self, l1, l2):
# 分别入栈
stack1 = []
stack2 = []
while l1:
stack1.append(l1.val)
l1 = l1.next
while l2:
stack2.append(l2.val)
l2 = l2.next
flag = 0
head = None
while stack1 or stack2 or flag != 0:
if stack1:
flag += stack1.pop()
if stack2:
flag += stack2.pop()
node = ListNode(flag % 10)
node.next = head
head = node
flag = flag // 10
return head
```
![](../../Pictures/qrcode.jpg)
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment