12-复杂数据结构
1.积分图前缀和
303. 区域和检索 - 数组不可变
class NumArray {
vector<int> num;
public:
NumArray(vector<int>& nums):num(nums) {
partial_sum(num.begin(),num.end(),num.begin());
}
int sumRange(int left, int right) {
return left > 0 ? num[right] - num[left - 1] : num[right];
}
};
304. 二维区域和检索 - 矩阵不可变
class NumMatrix {
vector<vector<int>> res;
public:
NumMatrix(vector<vector<int>>& matrix) :res(matrix.size() + 1, vector<int>(matrix[0].size() + 1,0)){
for(int i = 1; i < res.size();i++)
{
for(int j = 1; j < res[0].size();j++)
{
res[i][j] = res[i - 1][j] + res[i][j - 1] + matrix[i - 1][j - 1] - res[i - 1][j - 1];
}
}
}
int sumRegion(int row1, int col1, int row2, int col2) {
return res[row2 + 1][col2 + 1] - res[row1][col2 + 1] -res[row2 + 1][col1] + res[row1][col1];
}
};
560. 和为 K 的子数组
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
unordered_map<int,int> umap;
partial_sum(nums.begin(),nums.end(),nums.begin());
umap[0] = 1;
int res = 0;
for(int i = 0;i < nums.size();i++)
{
res += umap[nums[i] - k];
umap[nums[i]]++;
}
return res;
}
};
1031. 两个非重叠子数组的最大和***
class Solution {
public:
int maxSumTwoNoOverlap(vector<int>& nums, int firstLen, int secondLen) {
int res_max = 0;
partial_sum(nums.begin(),nums.end(),nums.begin());
nums.insert(nums.begin(),0);
auto f = [&](int firstLen , int secondLen){
int maxSumA = 0;
for(int i = firstLen + secondLen; i < nums.size();i++)
{
maxSumA = max(maxSumA, nums[i - secondLen] - nums[i - secondLen - firstLen]);
res_max = max(res_max, maxSumA + nums[i] - nums[i - secondLen]);
}
};
f(firstLen,secondLen);
f(secondLen,firstLen);
return res_max;
}
};
523. 连续的子数组和**
class Solution {
public:
bool checkSubarraySum(vector<int>& nums, int k) {
partial_sum(nums.begin(),nums.end(),nums.begin());
unordered_set<int> uset;
for(int i = 0; i < nums.size();i++)
{
if(nums[i] % k == 0 && i >= 1) return true;
if(uset.count(nums[i] % k) > 0) return true;
uset.insert(nums[i] % k);
}
return false;
}
};
974. 和可被 K 整除的子数组
class Solution {
public:
int subarraysDivByK(vector<int>& nums, int k) {
int sum = 0 , res = 0;
unordered_map<int,int> umap;
umap[0] = 1;
for(int i : nums)
{
sum += i;
int psum = (sum % k + k) % k;
if(umap[psum] > 0) res += umap[psum];
umap[psum]++;
}
return res;
}
};
2.前缀树
208. 实现 Trie (前缀树)
class Trie {
vector<Trie*> next;
char ch;
bool is_end;
public:
Trie() :is_end(false){
next.resize(26);
}
void insert(string word) {
Trie* cur = this;
for(char x:word)
{
if(!cur->next[x - 'a'])cur->next[x - 'a'] = new Trie();
cur = cur->next[x - 'a'];
cur->ch = x;
}
cur->is_end = true;
}
bool search(string word) {
Trie* cur = this;
for(char x:word)
{
if(!cur->next[x - 'a']) return false;
cur = cur->next[x - 'a'];
}
return cur->is_end;
}
bool startsWith(string prefix) {
Trie* cur = this;
for(char x:prefix)
{
if(!cur->next[x - 'a']) return false;
cur = cur->next[x - 'a'];
}
return true;
}
};
LCR 063. 单词替换
class Solution {
class Trie {
class dicttree
{
public:
char val;
bool isWord;
vector<dicttree*> trees;
dicttree()
{
val = 0;
isWord = false;
trees.resize(26);
for (int i = 0; i < 26; ++i) {
trees[i] = nullptr;
}
}
};
dicttree *root;
public:
Trie() {
root = new dicttree();
}
void insert(string word) {
dicttree * cur = root;
for (int i = 0; i < word.size(); ++i) {
if (cur->trees[word[i] - 'a'] == NULL)
{
cur->trees[word[i] - 'a'] = new dicttree();
cur->trees[word[i] - 'a']->val = word[i];
}
cur = cur->trees[word[i] - 'a'];
}
cur->isWord = true;
}
string search(string word) {
dicttree * cur = root;
for (int i = 0; i < word.size(); ++i) {
if (cur->trees[word[i] - 'a'] == NULL) return word;
cur = cur->trees[word[i] - 'a'];
if(cur->isWord) return word.substr(0,i + 1);
}
return word;
}
};
public:
string replaceWords(vector<string>& dictionary, string sentence) {
Trie* tree = new Trie();
for(int i = 0 ; i < dictionary.size();i++)
{
tree->insert(dictionary[i]);
}
string res,temp;
stringstream ss(sentence);
while(getline(ss,temp,' '))
{
res += tree->search(temp) + " ";
}
if(res.back() == ' ') res.pop_back();
return res;
}
};
LCR 064. 实现一个魔法字典
class MagicDictionary {
vector<string> dictionary;
public:
/** Initialize your data structure here. */
MagicDictionary() {
}
void buildDict(vector<string> dictionary) {
this->dictionary = dictionary;
}
bool search(string searchWord) {
for(int i = 0;i < dictionary.size() ;i++)
{
if(searchWord.size() != dictionary[i].size()) continue;
int sums = 0;
for(int j = 0; j < searchWord.size() ;j++)
{
if(dictionary[i][j] != searchWord[j]) sums++;
}
if(sums == 1) return true;
}
return false;
}
};
LCR 066. 键值映射
class MapSum {
unordered_map<string,int> umap;
public:
/** Initialize your data structure here. */
MapSum() {
}
void insert(string key, int val) {
umap[key] = val;
}
int sum(string prefix) {
int sums = 0;
for(auto x : umap)
{
if(x.first.size() >= prefix.size() && x.first.substr(0,prefix.size()) == prefix) sums += x.second;
}
return sums;
}
};
LCR 065. 单词的压缩编码
class Solution {
class Trie {
vector<Trie*> next;
char ch;
bool is_end;
public:
Trie() :is_end(false){
next.resize(26);
}
void insert(string word) {
Trie* cur = this;
for(char x:word)
{
if(!cur->next[x - 'a'])cur->next[x - 'a'] = new Trie();
cur = cur->next[x - 'a'];
cur->ch = x;
}
cur->is_end = true;
}
bool search(string word) {
Trie* cur = this;
for(char x:word)
{
if(!cur->next[x - 'a']) return false;
cur = cur->next[x - 'a'];
}
return cur->is_end;
}
bool startsWith(string prefix) {
Trie* cur = this;
for(char x:prefix)
{
if(!cur->next[x - 'a']) return false;
cur = cur->next[x - 'a'];
}
return true;
}
};
public:
int minimumLengthEncoding(vector<string>& words) {
Trie *tree = new Trie();
for(auto &x :words) reverse(x.begin(),x.end());
sort(words.begin(),words.end(),[&](const string &a,const string &b){
return a.size() > b.size();
});
int sum = 0;
for(auto x :words)
{
if(!tree->startsWith(x))
{
tree->insert(x);
sum += x.size() + 1;
}
}
return sum;
}
};
LCR 067. 数组中两个数的最大异或值
class Solution {
class dictTree
{
vector<dictTree*> next;
int val;
public:
dictTree():next(vector<dictTree*>(2)){};
void insert(int num)
{
dictTree* cur = this;
for(int i = 0; i <= 30 ;i++)
{
int bit = 1 & (num >> (30 - i));
if(!cur->next[bit]) cur->next[bit] = new dictTree();
cur = cur->next[bit];
}
cur->val = num;
}
int search(int num)
{
dictTree* cur = this;
for(int i = 0; i <= 30 ;i++)
{
int bit = 1 & (num >> (30 - i));
if(cur->next[1 - bit]) cur = cur->next[1 - bit];
else cur = cur->next[bit];
}
return cur->val ^ num;
}
};
public:
int findMaximumXOR(vector<int>& nums) {
dictTree * tree = new dictTree();
int maxs = 0;
for(int num: nums)
{
tree->insert(num);
maxs = max(maxs,tree->search(num));
}
return maxs;
}
};
386. 字典序排数
class Solution {
public:
vector<int> lexicalOrder(int n) {
vector<int> res;
function<void(int)> dfs = [&](int i)
{
if(i > n) return;
res.push_back(i);
for(int j = 0;j <= 9;j++)
{
dfs(i * 10 + j);
}
};
for(int i = 1;i <= 9;i++)dfs(i);
return res;
}
};
440. 字典序的第K小数字
class Solution {
using LL = long long;
int getNodes(LL u, int n)
{
LL next = u + 1; //当前根结点的右边的根结点
int totNodes = 0;//记录当前结点的所有节点数(包括它本身)
while(u <= n)
{
totNodes += min(n - u + 1, next - u);
u *= 10;//当前根结点下移
next *= 10;//当前根结点的右根结点下移
}
return totNodes;
}
public:
int findKthNumber(int n, int k) {
LL cur = 1;
while(k > 1)
{
int nodes = getNodes(cur, n); //求出cur下面的节点个数
if(k > nodes)
{
k -= nodes;
cur ++;//右移
}
else
{
k--;//下移
cur = cur * 10;
}
}
return (LL)cur;
}
};
1233. 删除子文件夹
class Solution {
struct tree
{
tree(string path,bool is_end):path(path),is_end(is_end){};
string path;
bool is_end;
unordered_map<string,tree*> umap;
};
tree* root;
public:
vector<string> removeSubfolders(vector<string>& folder) {
sort(folder.begin(),folder.end(),[](const string &a , const string &b){
return a.size() < b.size();
});
root = new tree("",false);
vector<string> res;
for(string x: folder)
{
//加入字典树
stringstream ss(x.substr(1) + "/");
string tmp;
tree *cur = root;
bool flas = false;
while(getline(ss,tmp,'/'))
{
//cout << tmp << endl;
if(cur->umap.find(tmp) ==cur->umap.end())
{
cur->umap[tmp] = new tree(tmp,false);
}
if(cur->is_end)
{
flas = true;
break;
}
else cur = cur->umap[tmp];
}
if(flas) continue;
cur->is_end = true;
res.push_back(x)
}
return res;
}
};
211. 添加与搜索单词 - 数据结构设计
class WordDictionary {
struct Tree
{
bool isWord;
vector<Tree*> next;
Tree():isWord(false),next(26){};
};
Tree *root;
public:
WordDictionary() {
root = new Tree();
}
void addWord(string word) {
Tree *cur = root;
for(char ch : word)
{
if(!cur->next[ch - 'a']) cur->next[ch - 'a'] = new Tree();
cur = cur->next[ch - 'a'];
}
cur->isWord = true;
}
bool search(string &word,int begin,Tree * cur) {
//if(begin == word.size()) return true;
for(int i = begin;i < word.size();i++)
{
char ch = word[i];
if(ch != '.')
{
if(!cur->next[ch - 'a']) return false;
else cur = cur->next[ch - 'a'];
}
else
{
bool flag = false;
for(char c = 'a';c <= 'z';c++)
{
if(cur->next[c - 'a'])flag = flag || search(word,i + 1,cur->next[c - 'a']);
}
return flag;
}
}
return cur->isWord;
}
bool search(string word) {
return search(word,0,root);
}
};
3.TreeMap红黑树
729. 我的日程安排表 I***
class MyCalendar {
public:
MyCalendar() {
}
bool book(int start, int end) {
auto pos = cmap.lower_bound(start);
auto epos = cmap.lower_bound(end);
if(pos == epos){
if(pos != cmap.begin() && (--pos)->second>start) return false;
cmap[start] = end;
return true;
}
return false;
}
map<int, int> cmap;
};
846. 一手顺子
class Solution {
public:
bool isNStraightHand(vector<int>& hand , int groupSize) {
if(groupSize == 1) return true;
if(hand.size() % groupSize != 0)return false;
map<int,int> cmap;
for(int x : hand) cmap[x]++;
while(!cmap.empty())
{
int pre = cmap.begin()->first;
cmap[pre]--;
if(cmap[pre] == 0) cmap.erase(pre);
for(int i = 1; i < groupSize;i++)
{
if(cmap[pre + i] == 0) return false;
else
{
cmap[pre + i]--;
if(cmap[pre + i] == 0) cmap.erase(pre + i);
}
}
}
return true;
}
};
4.其余数据结构
146. LRU 缓存
我们采用一个链表 list来储存信息的 key 和 value,链表的链接顺序即为最 近使用的新旧顺序,最新的信息在链表头节点。同时我们需要一个嵌套着链表的迭代器的 unordered_map 进行快速搜索,存迭代器的原因是方便调用链表的 splice 函数来直接更新查找成功(cash hit)时的信息,即把迭代器对应的节点移动为链表的头节 点。
list::splice实现list拼接的功能。将源list的内容部分或全部元素删除,拼插入到目的list。
函数有以下三种声明:
void list::splice( iterator pos, list rhs );
void list::splice( iterator pos, list rhs, iterator ix );
void list::splice( iterator pos, list rhs, iterator first, iterator last );
splice()把一个或一级元素从一个 list 移到另一个中去 它有三种形式
1、从positon开始,把一个 list rhs的全部元素搬移到另一个中去 pos开始
2、从positon开始,把一个 ix 元素搬移到 rhs 的 pos位置
3、从positon开始,把first 到 last 剪接到要操作的list对象中的pos位置
class LRUCache {
int capacitys;
list<pair<int,int>> lists;
unordered_map<int,list<pair<int, int>>::iterator> umap;
public:
LRUCache(int capacity): capacitys(capacity){
}
int get(int key) {
if(umap.find(key) == umap.end()) return -1;
else
{
lists.splice(lists.begin(), lists, umap[key]);
return umap[key]->second;
}
}
void put(int key, int value) {
if(umap.find(key) != umap.end())
{
umap[key]->second = value;
lists.splice(lists.begin(), lists, umap[key]);
return;
}
if(capacitys == umap.size())
{
pair<int,int> pir = lists.back();
lists.pop_back();
umap.erase(pir.first);
}
lists.push_front(pair<int,int>(key,value));
umap[key] = lists.begin();
}
};
LCR 030. O(1) 时间插入、删除和获取随机元素
class RandomizedSet {
unordered_map<int,int> umap;
vector<int> res;
public:
/** Initialize your data structure here. */
RandomizedSet() {
}
/** Inserts a value to the set. Returns true if the set did not already contain the specified element. */
bool insert(int val) {
if(umap.find(val) != umap.end()) return false;
res.push_back(val);
umap[val] = res.size() - 1;
return true;
}
/** Removes a value from the set. Returns true if the set contained the specified element. */
bool remove(int val) {
if(umap.find(val) == umap.end()) return false;
umap[res.back()] = umap[val];
swap(res[umap[val]],res[res.size() - 1]);
umap.erase(val);
res.pop_back();
return true;
}
/** Get a random element from the set. */
int getRandom() {
int pos = rand() % res.size();
return res[pos];
}
};
745. 前缀和后缀搜索
class WordFilter {
unordered_map<string, vector<int>> prefixMap;
unordered_map<string, vector<int>> suffixMap;
public:
WordFilter(vector<string>& words) {
for (int i = 0; i < words.size(); i++) {
string word = words[i];
int len = word.length();
for (int j = 0; j <= len; j++) {
prefixMap[word.substr(0, j)].push_back(i);
suffixMap[word.substr(j)].push_back(i);
}
}
}
int f(string pref, string suff) {
vector<int>& prefixIndexes = prefixMap[pref];
vector<int>& suffixIndexes = suffixMap[suff];
int i = prefixIndexes.size() - 1;
int j = suffixIndexes.size() - 1;
while (i >= 0 && j >= 0) {
if (prefixIndexes[i] == suffixIndexes[j]) {
return prefixIndexes[i];
} else if (prefixIndexes[i] > suffixIndexes[j]) {
i--;
} else {
j--;
}
}
return -1;
}
};
1146. 快照数组
class SnapshotArray {
unordered_map<int,map<int,int>> data;//每个位置用map保存对应版本号
int version;
public:
SnapshotArray(int length):data(length) {
version = 0;
}
void set(int index, int val) {
data[index][version] = val;
}
int snap() {
return version++;
}
int get(int index, int snap_id) {
if(data.count(index) == 0) return 0;
auto it = data[index].upper_bound(snap_id);
if(it != data[index].begin()) {
return (--it)->second;
}
return 0;
}
};