六大模块:容器、容器适配器、迭代器、算法、仿函数、空间适配器
1.Stack_栈
LC_20.有效的括号
给定一个只包括 ‘(‘,’)’,’{‘,’}’,’[‘,’]’ 的字符串,判断字符串是否有效。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26bool isValid(string s) {
int n = s.size();
if (n % 2 == 1)
return false;
//保存映射关系
unordered_map<char, char> vis = {
{')', '('},
{']', '['},
{'}', '{'}
}; //key \ value
//find: 查找key是否存在 connt:存在返回1,不存在返回0
stack<char>stk;
for (int i = 0; i < s.size(); i++) {
if (vis.count(s[i]))
{ //出现的是左括号
if (stk.empty() || vis[s[i]] != stk.top())
return false;
stk.pop();
}
else //出现的是右括号
stk.push(s[i]);
}
return stk.empty();
}
LC_32.最长有效括号
给定一个只包含 ‘(‘ 和 ‘)’ 的字符串,找出最长的包含有效括号的子串的长度。
子串:最长子串、最长子串、最长子串、最长子串、最长子串、最长子串
输入: “(()”
输出: 2
解释: 最长有效括号子串为 “()”
输入: “)()())”
输出: 4
解释: 最长有效括号子串为 “()()”
解题:
- stack找到有效的括号,利用辅助vis(false,true)
- 然后找到最长的连续区间即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33int longestValidParentheses(string s) {
//题目的意思是子串,所以先找到符合的做出判断
//再使用滑动区间找寻
stack<int>arr;
vector<bool>vis(s.size(), true);
for (int i = 0; i < s.size(); i++) {
if (s[i] == '(')
arr.push(i);
else {
if (arr.empty())
vis[i] = false; //没有匹配的括号
else
arr.pop();
}
}
while (!arr.empty()) {
vis[arr.top()] = false;
arr.pop();
}
int res = 0;
int len = 0;
for (int i = 0; i < vis.size(); i++) {
if (vis[i] == false) {
len = 0;
continue;
}
len++;
res = max(len, res);
}
return res;
}
LC_32.剑指09两个栈实现队列
解题:用一个辅助栈来过一次手
1 | class CQueue { |
单调栈问题
入栈元素小标
进行比较的是栈顶元素
模板
1
2
3
4
5
6
7
8
9stack<int>minn;
for (int i = 0; i < len; i++) {
while (!minn.empty() && T[i] > T[minn.top()]) {
minn.pop();
}
minn.push(i);
}
LC_739. 每日温度(找右边第一个比他大的数—递减栈)
请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。
例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。
1 | vector<int>dailyTemperatures(vector<int>& T) { |
LC_84. 柱状图中最大的矩形
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
他的最大面积:高*宽,每个高度能把他包住都算一次。
宽度:左边第一个比他小的,右边第一个比他小的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22int largestRectangleArea(vector<int>& heights) {
//为了当只存在一个元素时,也能计算
heights.push_back(0);
//相当于维护一个递增栈
int len = heights.size();
int res = 0;
//靠单调栈、靠特性:递增栈,下面的第一个元素肯定比他小
//找到右边第一个比他小的数、左边第一个比他小的数字
stack<int>maxx;
for (int i = 0; i < len; i++) {
while (!maxx.empty() && heights[i] < heights[maxx.top()]) {
int temp = maxx.top();
maxx.pop();
res = max(res, heights[temp] * (maxx.empty() ? i : (i - maxx.top() - 1)));
} //高度 宽度
maxx.push(i);
}
return res;
}
容器盛水问题
给定一个整形数组arr,已知其中所有的值都是非负的,将这个数组看作一个容器,请返回容器能装多少水。
、
1 | long long maxWater(vector<int>& arr) { |
2.Map_映射表
A.count() \ A.find()
成员函数
- auto it = A.find(key)
- if(it == A.end())没查找到
- count(key)返回0或者1
350. 两个数组的交集 II
给定两个数组,编写一个函数来计算它们的交集。
输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2,2]
有序的做法 / 无序的做法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38//无序:哈希表
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
if (nums1.size() == 0 || nums2.size() == 0)
return {};
unordered_map<int, int>m;
for (auto num : nums1)
m[num]++;
vector<int>res;
for (auto num : nums2) {
if (m.count(num))
{
res.push_back(num);
m[num]--;
if (m[num] == 0)
m.erase(num);
}
}
return res;
}
//有序时:双指针
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
sort(nums1.begin(), nums1.end());
sort(nums2.begin(), nums2.end());
vector<int> res;
int i = 0;
int j = 0;
while (i < nums1.size() && j < nums2.size())
if (nums1[i] < nums2[j]) i++;
else if (nums1[i] > nums2[j]) j++;
else {
res.push_back(nums1[i]);
i++, j++;
}
return res;
}
LC_1.两数之和
数组中找两个元素之和为target
解法:暴力:time——O(n^2),空间——O(1)
- 哈希表:time——O(n),空间——O(n)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25vector<int> twoSum(vector<int>& nums, int target)
{
//vector<int>a;
//暴力O(n^2)
// for(int i=0;i!=nums.size();i++)
// {
// for(int j=i;j!=nums.size();j++)
// {
// if(nums[i]+nums[j]==target&&i!=j)
// {
// a.push_back(i);
// a.push_back(j);
// }
// }
// }
unordered_map<int, int>vis;//存放元素值,和元素下标
for (int i = 0; i < nums.size(); i++) {
auto iter = vis.find(target - nums[i]);
if (iter != vis.end()) {
return { i,iter->second };
}
vis.emplace(nums[i], i);
}
return {};
}
LC_387.字符串中的第一个唯一字符
给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。
解法:哈希表
1 | //时间复杂度n,空间复杂度n |
3.Set_集合
成员函数
- 初始化:unordered_set< string >res (words.begin(),words.end()); //vector< string > & words
LC_820.单词的压缩编码
给定一个单词列表,我们将这个列表编码成一个索引字符串 S 与一个索引列表 A。
例如,如果这个列表是 [“time”, “me”, “bell”],我们就可以将其表示为 S = “time#bell#” 和 indexes = [0, 2, 5]。
对于每一个索引,我们可以通过从字符串 S 中索引的位置开始读取字符串,直到 “#” 结束,来恢复我们之前的单词列表。
那么成功对给定单词列表进行编码的最小字符串长度是多少呢?
输入: words = [“time”, “me”, “bell”]
输出: 10
说明: S = “time#bell#” , indexes = [0, 2, 5] 。
1 | int minimumLengthEncoding(vector<string>& words) { |
4.Queue_单向队列
成员函数
- A.push();
- A.front();//返回元素
- A.back(); //返回元素
- A.pop();
LC_225. 用队列实现栈
进入之后,N-1个元素再重新进
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29queue<int>arr;
void push(int x) {
arr.push(x);
int size = arr.size();
for (int i = 0; i < size - 1; i++) {
int temp = arr.front();
arr.push(temp);
arr.pop();
}
}
int pop() {
if (arr.empty())
return -1;
else {
int temp = arr.front();
arr.pop();
return temp;
}
}
int top() {
return arr.front();
}
bool empty() {
return arr.empty();
}
5.deque_双向队列
239. 区间的滑动窗口最大值
给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
题目:
输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
输出: [3,3,5,5,6,7]
解释:
滑动窗口的位置 —– 最大值
[1 3 -1] -3 5 3 6 7 —– 3
1 [3 -1 -3] 5 3 6 7 —– 3
1 3 [-1 -3 5] 3 6 7 —– 5
1 3 -1 [-3 5 3] 6 7 —– 5
1 3 -1 -3 [5 3 6] 7 —– 6
1 3 -1 -3 5 [3 6 7] —– 7
解题:
利用双向队列的堆栈特性
pop_back()\ pop_front() \ push_back()\ push_front()\ A.front()\ A.back()
- 头部保存最大元素
- 利用存放元素下标来保证没有超出区间的范围
- 每次比较和尾部数据进行比较,从而保证前面节点:老元素。后面节点:新元素。这样可以完成上一条。
1 | vector<int> maxSlidingWindow(vector<int>& nums, int k) { |
6.list_双向链表
成员函数
- A.erase(迭代器)
LC_146. LRU缓存机制
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。
获取数据 get(key) - 如果关键字 (key) 存在于缓存中,则获取关键字的值(总是正数),否则返回 -1。
写入数据 put(key, value) - 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字/值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
例题:
LRUCache cache = new LRUCache( 2 /* 缓存容量 */ );
cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // 返回 1
cache.put(3, 3); // 该操作会使得关键字 2 作废
cache.get(2); // 返回 -1 (未找到)
cache.put(4, 4); // 该操作会使得关键字 1 作废
cache.get(1); // 返回 -1 (未找到)
cache.get(3); // 返回 3
cache.get(4); // 返回 4
题解:
- 利用list存储元素,从而保证时序性
- 利用unordered_map存储list的iterator,从而保证删除、查找的时间
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64class LRUCache {
public:
LRUCache(int capacity) {
size = capacity;
}
list<pair<int, int>>arr;
unordered_map<int, list<pair<int, int>>::iterator>vis;
//list<pair<int,int>>arr;
//unordered_map<key,arr::iterator>vis;
//存放迭代器是为了便于删除和查找
int get(int key) {
//it是key值
auto it = vis.find(key);
if (it == vis.end()) {
return -1;
}
else {
//放到前面去
pair<int, int>temp = *vis[key];//迭代器解引就是对应值
arr.erase(vis[key]);
arr.push_front(temp);
vis[key] = arr.begin();
return temp.second;
}
}
void put(int key, int value) {
auto it = vis.find(key);
//不存在
if (it == vis.end()) {
if (arr.size() == size) {
//删除尾元素
pair<int, int>temp = arr.back();
//双删除
int deleteKey = temp.first;
vis.erase(deleteKey);
arr.pop_back();
arr.push_front({ key,value });
vis[key] = arr.begin();
}
else {
arr.push_front({ key,value });
vis[key] = arr.begin();
}
}
//存在
else {
//存在只需要放到前面去,list删除只能用迭代器
arr.erase(vis[key]);
arr.push_front({ key,value });
vis[key] = arr.begin();
}
}
private:
int size;
};
7.vector_动态数组
成员函数:
copy(src_Begin, src_End , dest_Begin)Copy:归并算法会使用到
copy(B.begin() , B.end(), A.begin());
- OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result)
erase(iterator position)//返回下元素指针
insert函数
insert( dest_插入数组的位置, src_输入开始位置 , dest_输入结束位置)分类:
- 单一元素(1)——A.insert (iterator position, const value_type& val);
- 相同元素(2)——A.insert (iterator position, size_type n, const value_type& val);
- 范围元素(3)——使用广泛——A.insert (iterator position, InputIterator first, InputIterator last);