目录
〇,全文说明、宏定义代码
类里面和宏定义处都有接口注释,因为宏不体现具体参数,所以注释以类里面的为准。
代码工程结构:
- 每一章的第一节《代码》可以独立编译运行(本地要加LOCAL宏)
- 每一章的第二节《测试代码》搭配第〇章的代码和本章第一节的代码可以编译运行并测试成功
- 所有模板文章的第〇章的代码和其他章第一节的《代码》全部汇总起来可以编译运行
宏定义代码:
#define LOCAL //力扣不要本行代码,其他OJ随意
///(1)输入输出///
#define Print(x) cout << endl << #x << " = "; INOUT::print(x);//输出数据
#define Read(x) INOUT::read(x);//读入数据
///(2)单vector操作///
#define Frev SingleVectorOpt::frev//翻转vector、翻转二维vector的每一行
#define Foverturn SingleVectorOpt::foverturn//沿主对角线(左上角到右下角)翻转二维vector
#define Frotation SingleVectorOpt::frotation//顺时针旋转二维vector
#define DeletAllX SingleVectorOpt::deletAllX//从vector(一维或2维)中删除所有的x
#define DeleteNeiborSame SingleVectorOpt::deleteNeiborSame// 去掉相邻重复元素
#define GetDifNum SingleVectorOpt::getDifNum//判断数组去掉相邻重复数之后有多少个不同的数
#define Fcheng SingleVectorOpt::fcheng//vector乘一个数
#define Fjia SingleVectorOpt::fjia//vector加一个数
#define SortEveryLine SingleVectorOpt::sortEveryLine//二维数组每一行排序
#define FirstInLeft SingleVectorOpt::firstInLeft//返回vector每个数前面最近的满足pr关系的数的ID,-1 或者 0到size-1
#define Fminlef SingleVectorOpt::fminlef//返回vector每个数前面最近的比它小的数的ID,-1 或者 0到size-1
#define Fminlef2 SingleVectorOpt::fminlef2//返回vector每个数前面最近的比它小或等于的数的ID,-1 或者 0到size-1
#define Fmaxlef SingleVectorOpt::fmaxlef//返回vector每个数前面最近的比它大的数的ID,-1 或者 0到size-1
#define Fmaxlef2 SingleVectorOpt::fmaxlef2//返回vector每个数前面最近的比它大或等于的数的ID,-1 或者 0到size-1
#define Fminrig SingleVectorOpt::fminrig//返回vector每个数后面最近的比它小的数的ID,size 或者 0到size-1
#define Fminrig2 SingleVectorOpt::fminrig2//返回vector每个数后面最近的比它小或等于的数的ID,size 或者 0到size-1
#define Fmaxrig SingleVectorOpt::fmaxrig//返回vector每个数后面最近的比它大的数的ID,size 或者 0到size-1
#define Fmaxrig2 SingleVectorOpt::fmaxrig2//返回vector每个数后面最近的比它大或等于的数的ID,size 或者 0到size-1
#define SplitAtHalf SingleVectorOpt::splitAtHalf//求任意段和的中分位置
///(3)vector拆分拼接、择优合并///
#define FvecJoin VectorJoin::fvecJoin //2个vector(一维或2维)左右拼接起来
#define VecSplit VectorJoin::vecSplit//把v分成前面k个和后面的v.size()-k个,返回拆出来的后面的数组,v本身只留k个
#define LoopSplit VectorJoin::loopSplit//把{1,2,3,4,5,6,7}循环拆分成{1,4,7}{2,5}{3,6}
#define CrossChange VectorJoin::crossChange//交叉交换,v1分成前面k1个和后面的v1.size()-k1个,v2同理,交换后面的2段
#define MergeVector VectorJoin::mergeVector //vector的择优合并
#define FoldJoin VectorJoin::foldJoin//二维vector拼接转化成一维的
#define SelfCopyJoin VectorJoin::selfCopyJoin//把vector自复制一份,前后拼接起来
///(4)vector的索引、数据域拓展和提取、拓展排序、逆置换///
#define Fshr VectorOpt::fshr//收缩计数,把[1 4 4 1]变成[(1,2)(4,2)]或[(1,1)(4,2)(1,1)]
#define Funshr VectorOpt::funshr//平摊,把 [(1,2)(4,2)]变成[1 1 4 4]
#define Fforeach VectorOpt::fforeach//生成枚举序号
#define ChangeMeiJu VectorOpt::changeMeiJu//根据各数字对应的替换列表,生成各种替代枚举
#define SubMeiJu VectorOpt::subMeiJu //根据各id对应的替换列表,生成各种替代枚举
#define ExpandWithId VectorOpt::expandWithId //拓展数据域,加上id
#define SortWithId VectorOpt::sortWithId//给vector拓展,加上id并拓展成稳定排序
#define SortWithOrderMatch VectorOpt::sortWithOrderMatch//给vector拓展,加上id,但只按照原数据进行排序
#define SortId VectorOpt::sortId//排序后数组中的每个数的原ID,输入8 5 6 7,输出1 2 3 0
#define SortId2 VectorOpt::sortId2//每个数在排序后的数组中的ID,输入8 5 6 7,输出3 0 1 2
#define SortExtend VectorOpt::sortExtend//给v排序,v2按照同样的顺序调整,输入{1,3,2}{4,5,6},输出{1,2,3}{4,6,5}
#define FindSum VectorOpt::findSum//2个vector中寻找和为s的对,返回结果的每一行都是[id1,id2]
#define CmpVector VectorOpt::cmpVector//vector的字典序比较,v1<v2是true,v1>=v2是false
#define SortVector VectorOpt::sortVector//vector的字典序排序
///(5)vector的计算///
#define VecAdd VectorCal::vecAdd//2个vector相加
#define EverySum VectorCal::everySum//枚举2个vector的两数之和
#define VecIsSame VectorCal::vecIsSame//判断2个vector(一维或二维)是否全等
#define DeleteSameLine VectorCal::deleteSameLine//二维数组去掉重复行
#define HaveSameData VectorCal::haveSameData//判断vector中是否含有重复元素
#define DeleteLineWithSameDatas VectorCal::deleteLineWithSameDatas//删除二维vector中,含有重复元素的行
#define VecConvolution VectorCal::vecConvolution//2个vector的卷积
///(6)单链表///
#define InitLinkList LinkList::initLinkList//构建链表
#define OutLinkList LinkList::outLinkList//打印链表
#define LinkGetLength LinkList::linkGetLength//获取链表长度
#define IsSameLinkList LinkList::isSameLinkList//两个链表的数据是否全等
#define LinkReverse LinkList::linkReverse//链表反转,返回新的head
#define GetKthFromEnd LinkList::getKthFromEnd//链表中倒数第k个节点
#define GetTail LinkList::getTail//链表最后一个节点
#define LinkSplit LinkList::linkSplit//留下前k个节点,把后面的切下来并返回
#define LinkMerge LinkList::linkMerge//直接合并2个链表
#define MergeTwoLists LinkList::mergeTwoLists//把两个链表交叉合并为一个链表
#define MergeTwoUpLists LinkList::mergeTwoUpLists//把两个升序的链表合并为一个升序的链表
#define ListToVec LinkList::listToVec//把链表转化成结构体指针数组
#define VecToList LinkList::vecToList//把结构体指针数组转化成链表
#define SortLinkList LinkList::sortLinkList//链表排序
#define GetAnyoneInCycle LinkList::getAnyoneInCycle//求链表环中任意节点,没环返回NULL
#define GetCycleLen LinkList::getCycleLen//求链表环的长度,没环返回0
#define GetFirstInCycle LinkList::getFirstInCycle//求链表环的第一个节点,没环返回NULL
///(7)双向循环链表///
#define GetSingleDeList DeLinkList::getSingleDeList//创建单节点双向循环链表
#define MergeDelist DeLinkList::mergeDelist//合并双向循环链表
#define GetLengthOfDeLL DeLinkList::getLengthOfDeLL//获取链表长度
///(8.1)STL操作封装
#define VecGet StlBasicOpt::vecGet//获取列表某处的值
#define Finsert StlBasicOpt::finsert//id处覆盖或者添加一个数
#define DelOnlyOne StlBasicOpt::delOnlyOne//multi***容器x删除一个数值n
#define DelEnd StlBasicOpt::delEnd//删除最后一个元素
///(8.2)拓展数据结构///
// MinMaxStack 略。栈的拓展,支持获取最值,所有接口时间复杂度都是 O(1)
// MinMaxStack2 略。栈的拓展,支持删除最值,所有接口时间复杂度都在 O(log n)之内
// MinMaxQueue 略。队列的拓展,支持获取最值,所有接口的均摊时间复杂度都是O(1)
// QueueWithNoSameData 略。不含重复元素的队列
///(9)单调栈、单调队列、背包///
// MonotonicStack 略。单调栈
// MonotonicQueue 略。单调队列
// Pack 略。01背包、完全背包、多重背包、混合背包
// PackDoubleVolume 略。双代价背包
// PackGroup 略。分组背包
// PackGeneralize 略。泛化物品背包
// PackDepend 略。依赖背包(仅限森林)
一,输入输出
1,代码
//对输入输出进行了封装,利用重载让各种数据结构的输入输出都可以用统一的函数名,同时让输入和输出匹配。
//注意顺序是:基本数据类型、不含容器的自定义数据结构、容器、含容器的自定义数据结构。
const float theNan = 0.123456; //float默认输出只有6位
class INOUT
{
public:
//(1)基本类型
template<typename T>
static inline void print(T x)
{
cout << x << " ";
}
template<typename T>
static inline void read(T& x)
{
while (!(cin >> x)) { // only cin type T, ignore other info
cin.clear();
cin.ignore();
}
}
static void print(float x)
{
if (std::isnan(x)) cout << theNan << " ";
else cout << x << " ";
}
static void read(float& x)
{
read<float>(x);
if (x == theNan) x = NAN;
}
// (2)不含容器的自定义数据结构
//(3)容器
template<typename T1, typename T2>
static inline void print(const std::pair<T1, T2>& p)
{
print(p.first);
print(p.second);
}
template<typename T1, typename T2>
static inline void print(const map<T1, T2>& aMap)
{
cout << " size = " << aMap.size() << endl;
for (auto& it : aMap) {
print(it);
cout << endl;
}
}
template<typename T>
static inline void print(const vector<T>& vec)
{
cout << " size = " << vec.size() << endl;
for (auto& it : vec) {
print(it);
}
cout << endl;
}
template<typename T1, typename T2>
static inline void read(std::pair<T1, T2>& p)
{
read(p.first);
read(p.second);
}
template<typename Tkey, typename Tvalue>
static void read(std::map<Tkey, Tvalue>& aMap)
{
int num;
read(num);
std::pair<Tkey, Tvalue> p;
while (num--) {
read(p);
aMap[p.first] = p.second;
}
}
template<typename T>
static inline void read(vector<T>& vec)
{
int num;
read(num);
vec.resize(num); // 慎用
for (int i = 0; i < num; i++) {
read(vec[i]);
}
}
//(4)含容器的自定义数据结构
};
2,测试代码
bool testInOut()
{
vector<int>v;
// Read(v); // 输入3 100 200 300
// Print(v); // 输出"v = size = 3 \n 100 200 300"
return true;
}
int main()
{
if (testInOut())cout << "test succ!";
return 0;
}
二,单vector操作
1,代码
class SingleVectorOpt
{
public:
//翻转vector、翻转二维vector的每一行
template<typename T>
static vector<T> frev(const vector<T>& v)
{
vector<T> ans;
ans.resize(v.size());
for (int i = 0; i < v.size(); i++)ans[i] = v[v.size() - 1 - i];
return ans;
}
template<typename T>
static vector<vector<T>> frev(const vector<vector<T>>& v)
{
vector<vector<T>>ans;
for (int i = 0; i < v.size(); i++)ans.push_back(frev(v[i]));
return ans;
}
//沿主对角线(左上角到右下角)翻转二维vector
template<typename T>
static vector<vector<T>> foverturn(const vector<vector<T>>& v)
{
vector<vector<T>> ans(v[0].size());
for (int i = 0; i < v[0].size(); i++) {
ans[i].resize(v.size());
for (int j = 0; j < v.size(); j++)ans[i][j] = v[j][i];
}
return ans;
}
//顺时针旋转二维vector
template<typename T>
static vector<vector<T>> frotation(const vector<vector<T>>& v)
{
return frev(foverturn(v));
}
//从vector(一维或2维)中删除所有的x
template<typename T>
static void deletAllX(vector<T>& v, T x)
{
for (int i = 0; i < v.size(); i++)if (v[i] == x)v.erase(v.begin() + i--);
}
template<typename T>
static void deletAllX(vector<vector<T>>& v, T x)
{
for (auto& vi : v)deletAllX(vi, x);
}
// 去掉相邻重复元素
template<typename T>
static void deleteNeiborSame(vector<T>&v)
{
v.erase(std::unique(v.begin(), v.end()), v.end());
}
//判断数组去掉相邻重复数之后有多少个不同的数
template<typename T>
static int getDifNum(const vector<T>&v)
{
auto v2 = v;
deleteNeiborSame(v2);
return v2.size();
}
//vector乘一个数
template<typename T1, typename T2>
static void fcheng(vector<T1>& v, T2 n)
{
for (int i = v.size() - 1; i >= 0; i--)v[i] *= n;
}
//vector加一个数
template<typename T1, typename T2>
static void fjia(vector<T1>& v, T2 n)
{
for (int i = v.size() - 1; i >= 0; i--)v[i] += n;
}
//二维数组每一行排序
template<typename T>
static void sortEveryLine(vector<vector<T>>& v)
{
for (int i = 0; i < v.size(); i++)sort(v[i].begin(), v[i].end());
}
//返回vector每个数前面最近的满足pr关系的数的ID,-1 或者 0到size-1
template<typename T, class P>
static inline vector<int>firstInLeft(vector<T>v, P pr)
{
vector<int> ans;
if (v.size() == 0)return ans;
stack<T>st;
st.push(0);
ans.push_back(-1);
for (int i = 1; i < v.size(); i++) //代码用单调栈实现,时间复杂度为O(n)
{
while (!st.empty() && !pr(v[st.top()], v[i]))st.pop();
if (st.empty())ans.push_back(-1);
else ans.push_back(st.top());
st.push(i);
}
return ans;
}
//返回vector每个数前面最近的比它小的数的ID,-1 或者 0到size-1
template<typename T>
static vector<int> fminlef(vector<T> v)
{
return firstInLeft(v, [](T a, T b) {return a < b; }); //可换为自定义函数
}
//返回vector每个数前面最近的比它小或等于的数的ID,-1 或者 0到size-1
template<typename T>
static vector<int> fminlef2(vector<T> v)
{
return firstInLeft(v, [](T a, T b) {return a <= b; }); //可换为自定义函数
}
//返回vector每个数前面最近的比它大的数的ID,-1 或者 0到size-1
template<typename T>
static vector<int> fmaxlef(vector<T> v)
{
fcheng(v, -1);
vector<int>ans = fminlef(v);
return ans;
}
//返回vector每个数前面最近的比它大或等于的数的ID,-1 或者 0到size-1
template<typename T>
static vector<int> fmaxlef2(vector<T> v)
{
fcheng(v, -1);
vector<int>ans = fminlef2(v);
return ans;
}
//返回vector每个数后面最近的比它小的数的ID,size 或者 0到size-1
template<typename T>
static vector<int> fminrig(vector<T> v)
{
vector<int>v1 = frev(v), v2 = fminlef(v1);
fcheng(v2, -1);
fjia(v2, v.size() - 1);
return frev(v2);
}
//返回vector每个数后面最近的比它小或等于的数的ID,size 或者 0到size-1
template<typename T>
static vector<int> fminrig2(vector<T> v)
{
vector<int>v1 = frev(v), v2 = fminlef2(v1);
fcheng(v2, -1);
fjia(v2, v.size() - 1);
return frev(v2);
}
//返回vector每个数后面最近的比它大的数的ID,size 或者 0到size-1
template<typename T>
static vector<int> fmaxrig(vector<T> v)
{
vector<int>v1 = frev(v), v2 = fmaxlef(v1);
fcheng(v2, -1);
fjia(v2, v.size() - 1);
return frev(v2);
}
//返回vector每个数后面最近的比它大或等于的数的ID,size 或者 0到size-1
template<typename T>
static vector<int> fmaxrig2(vector<T> v)
{
vector<int>v1 = frev(v), v2 = fmaxlef2(v1);
fcheng(v2, -1);
fjia(v2, v.size() - 1);
return frev(v2);
}
// v中都是非负数,对于v的任意一段[low,high],求满足[low,id]总和大于等于[low,high]总和的一半的最小id
map<int, map<int, int>> splitAtHalf(vector<int>& v)
{
vector<int>s;
int n = 0;
s.push_back(n);
for (auto x : v) {
n += x;
s.push_back(n);
}
map<int, map<int, int>>ans;
for (int i = 0; i < v.size(); i++) {
int id = i;
for (int j = i; j < v.size(); j++) {
while (s[id + 1] - s[i] < s[j + 1] - s[id + 1])id++;
ans[i][j] = id;
}
}
return ans;
}
};
2,测试代码
//2个vector(一维或2维)左右拼接起来
template<typename T>
static vector<T> fvecJoin(const vector<T>& v1, const vector<T>& v2)
{
vector<T>ans(v1.size() + v2.size());
copy(v1.begin(), v1.end(), ans.begin());
copy(v2.begin(), v2.end(), ans.begin() + v1.size());
return ans;
}
//二维vector拼接转化成一维的
template<typename T>
static vector<T> foldJoin(const vector<vector<T>>& v)
{
vector<T>ans;
for (auto& vi : v)ans = fvecJoin(ans, vi);
return ans;
}
template<typename T>
static bool IsSame(const T &a, const T &b)
{
return a == b;
}
template<typename T>
static bool IsSame(const vector<T>& v1, const vector<T>& v2)
{
if (v1.size() - v2.size())return false;
for (int i = 0; i < v1.size(); i++)if (!IsSame(v1[i], v2[i]))return false;
return true;
}
template<typename T, typename T2>
static bool IsSame(const pair<T,T2>&p1, const pair<T, T2>&p2)
{
return IsSame(p1.first, p2.first) && IsSame(p1.second, p2.second);
}
#define EXPECT_EQ(a,b) if(!IsSame(a,b)){cout<<"ERROR!!!!!!!!!\n";return false;}
bool testSingleVectorOpt()
{
vector<int>v4{ 3,6 };
EXPECT_EQ(Frev(v4), (vector<int>{6, 3}));
vector<vector<char>> v{ {'a','b'},{'c','0'} };
EXPECT_EQ(foldJoin(v), (vector<char>{ 'a', 'b', 'c', '0' }));
EXPECT_EQ(foldJoin(Foverturn(v)), (vector<char>{ 'a', 'c', 'b', '0' }));
EXPECT_EQ(foldJoin(Frotation(v)), (vector<char>{ 'c', 'a', '0', 'b' }));
DeletAllX(v, '0');
EXPECT_EQ(foldJoin(v), (vector<char>{ 'a', 'b', 'c'}));
vector<int>v2{ 1,2,2,3,4,5,5,6 };
EXPECT_EQ(GetDifNum(v2), 6);
Fcheng(v2, 2);
Fjia(v2, 1);
EXPECT_EQ(v2, (vector<int>{3, 5, 5, 7, 9, 11, 11, 13}));
v[1].push_back('a');
EXPECT_EQ(foldJoin(v), (vector<char>{ 'a', 'b', 'c', 'a'}));
SortEveryLine(v);
EXPECT_EQ(foldJoin(v), (vector<char>{ 'a', 'b', 'a', 'c'}));
vector<int>v3{ 1,3,5,2,4 };
EXPECT_EQ(Fminlef(v3), (vector<int>{-1, 0, 1, 0, 3}));
return true;
}
int main()
{
if (testSingleVectorOpt())cout << "test succ!";
return 0;
}
三,Vector拆分拼接、择优合并
1,代码
class VectorJoin
{
public:
//2个vector(一维或2维)左右拼接起来
template<typename T>
static vector<T> fvecJoin(const vector<T>& v1, const vector<T>& v2)
{
vector<T>ans(v1.size() + v2.size());
copy(v1.begin(), v1.end(), ans.begin());
copy(v2.begin(), v2.end(), ans.begin() + v1.size());
return ans;
}
template<typename T>
static vector<vector<T>> fvecJoin(const vector<vector<T>>& v1, const vector<vector<T>>& v2)
{
vector<vector<T>>ans(v1.size());
for (int i = 0; i < v1.size(); i++)ans[i] = fvecJoin(v1[i], v2[i]);
return ans;
}
//把v分成前面k个和后面的v.size()-k个,返回拆出来的后面的数组,v本身只留k个
template<typename T>
static vector<T> vecSplit(vector<T>& v, int k)
{
vector<T>v2;
v2.resize(v.size() - k);
copy(v.begin() + k, v.end(), v2.begin());
v.resize(k);
return v2;
}
//把{1,2,3,4,5,6,7}循环拆分成{1,4,7}{2,5}{3,6}
template<typename T>
static vector<vector<T>> loopSplit(vector<T>& v, int num)
{
vector<vector<T>>v2(num);
for (int i = 0; i < v.size(); i++)v2[i % num].push_back(v[i]);
return v2;
}
//交叉交换,v1分成前面k1个和后面的v1.size()-k1个,v2同理,交换后面的2段
template<typename T>
static void crossChange(vector<T>& v1, vector<T>& v2, int k1, int k2)
{
vector<T>v3 = vecSplit(v1, k1), v4 = vecSplit(v2, k2);
v1 = fvecJoin(v1, v4), v2 = fvecJoin(v2, v3);
}
//vector的择优合并
template<typename T>
static vector<T> mergeVector(const vector<T>& a, const vector<T>& b)
{
vector<T> ans;
int i;
for (i = 0; i < a.size() && i < b.size(); i++) {
if (isGreater(a[i], b[i]))ans.push_back(a[i]);
else ans.push_back(b[i]);
}
for (; i < a.size(); i++)ans.push_back(a[i]);
for (; i < b.size(); i++)ans.push_back(b[i]);
return ans;
}
//二维vector拼接转化成一维的
template<typename T>
static vector<T> foldJoin(const vector<vector<T>>& v)
{
vector<T>ans;
for (auto& vi : v)ans = fvecJoin(ans, vi);
return ans;
}
//把vector自复制一份,前后拼接起来
template<typename T>
static vector<T> selfCopyJoin(const vector<T>& v)
{
return fvecJoin(v, v);
}
private:
template<typename T>
static bool isGreater(T a, T b)
{
return a > b;
}
};
2,测试代码
template<typename T>
static bool IsSame(const T &a, const T &b)
{
return a == b;
}
template<typename T>
static bool IsSame(const vector<T>& v1, const vector<T>& v2)
{
if (v1.size() - v2.size())return false;
for (int i = 0; i < v1.size(); i++)if (!IsSame(v1[i], v2[i]))return false;
return true;
}
template<typename T, typename T2>
static bool IsSame(const pair<T,T2>&p1, const pair<T, T2>&p2)
{
return IsSame(p1.first, p2.first) && IsSame(p1.second, p2.second);
}
#define EXPECT_EQ(a,b) if(!IsSame(a,b)){cout<<"ERROR!!!!!!!!!\n";return false;}
bool testVectorJoin()
{
EXPECT_EQ(FvecJoin(vector<int>{ 1, 2, 3 }, vector<int>{ 3, 5 }), (vector<int>{1, 2, 3, 3, 5}));
vector<int>v{ 2,2,4,7 }, v2{ 3,1,3,5 };
auto v3 = VecSplit(v, 3);
EXPECT_EQ(v, (vector<int>{2, 2, 4}));
EXPECT_EQ(v3, (vector<int>{7}));
v3 = MergeVector(v, v2);
EXPECT_EQ(v3, (vector<int>{3, 2, 4, 5})); //{2, 2, 4}和{ 3,1,3,5 } -> {3, 2, 4, 5}
v3 = SelfCopyJoin(v3);
EXPECT_EQ(v3, (vector<int>{3, 2, 4, 5, 3, 2, 4, 5}));
auto v4 = LoopSplit(v3, 3);
EXPECT_EQ(FoldJoin(v4), (vector<int>{3, 5, 4, 2, 3, 5, 4, 2 }));
CrossChange(v2, v3, 2, 3);
EXPECT_EQ(v2, (vector<int>{3, 1, 5, 3, 2, 4, 5}));
EXPECT_EQ(v3, (vector<int>{3, 2, 4, 3, 5}));
return true;
}
int main()
{
if (testVectorJoin())cout << "test succ!";
return 0;
}
四,vector的索引、数据域拓展和提取、拓展排序、逆置换
1,代码
class VectorOpt
{
public:
//收缩计数,把[1 4 4 1]变成canSort ? [(1,2)(4,2)] : [(1,1)(4,2)(1,1)]
template<typename T>
static vector<pair<T, int>> fshr(vector<T>v, bool canSort = true) //谨慎传引用
{
vector<pair<T, int>>ans;
if (v.size() == 0)return ans;
if (canSort)sort(v.begin(), v.end());
int low = 0;
for (int i = 1; i <= v.size(); i++) {
if (i == v.size() || v[i] != v[i - 1]) {
ans.push_back(make_pair(v[i - 1], i - low));
low = i;
}
}
return ans;
}
//平摊,把 [(1,2)(4,2)]变成[1 1 4 4]
template<typename T>
static vector<T> funshr(vector<pair<T, int>>& v)
{
vector<T>ans;
for (auto p : v) {
for (int i = 0; i < p.second; i++)ans.push_back(p.first);
}
return ans;
}
//生成枚举序号
template<typename T>
static vector<vector<int>> fforeach(const vector<vector<T>>& v)
{
int s = 1;
for (auto& vi : v)s *= vi.size();
vector<vector<int>> ans;
while (s--)
{
vector<int> vt;
int st = s;
for (int j = v.size() - 1; j >= 0; j--)
{
vt.insert(vt.begin(), st % v[j].size());
st /= v[j].size();
}
ans.push_back(vt);
}
return ans;
}
//根据各数字对应的替换列表,生成各种替代枚举
template<typename T>
static vector<vector<T>> changeMeiJu(const vector<T>& data, map<T, vector<T>>options)
{
vector<vector<T>> ans(1, data);
int len = data.size();
for (int i = 0; i < len; i++) {
int s = ans.size();
for (int j = 0; j < s; j++)for (auto op : options[data[i]]) {
vector<T> x = ans[j];
x[i] = op;
ans.push_back(x);
}
}
return ans;
}
//根据各id对应的替换列表,生成各种替代枚举
template<typename T>
static vector<T> subMeiJu(const T &data, int len, map<int, T>options)
{
vector<T> ans;
ans.push_back(data);
for (int i = 0; i < len; i++) {
int s = ans.size();
for (int j = 0; j < s; j++)for (auto op : options[i]) {
T x = ans[j];
x[i] = op;
ans.push_back(x);
}
}
return ans;
}
//拓展数据域,加上id
template<typename T>
static inline vector<pair<T, int>>expandWithId(const vector<T>& v)
{
vector<pair<T, int>>ans;
ans.resize(v.size());
for (int i = 0; i < v.size(); i++)ans[i].first = v[i], ans[i].second = i;
return ans;
}
//给vector拓展,加上id并拓展成稳定排序
template<typename T>
static inline vector<pair<T, int>> sortWithId(const vector<T>& v)
{
vector<pair<T, int>>ans = expandWithId(v);
sort(ans.begin(), ans.end(), cmpPair<T, int>);
return ans;
}
//给vector拓展,加上id,但只按照原数据进行排序
template<typename T>
static inline vector<pair<T, int>> sortWithOrderMatch(const vector<T>& v)
{
vector<pair<T, int>>ans = expandWithId(v);
sort(ans.begin(), ans.end(), cmpJustFirst<T, int>);
return ans;
}
//排序后数组中的每个数的原ID,输入8 5 6 7,输出1 2 3 0,也可以直接求逆置换
template<typename T>
static inline vector<int> sortId(const vector<T>& v)
{
auto vp = sortWithId(v);
vector<int>ans;
transform(vp.begin(), vp.end(), back_inserter(ans), [](const pair<T, int>& p) {return p.second; });
return ans;
}
//每个数在排序后的数组中的ID,输入8 5 6 7,输出3 0 1 2
template<typename T>
static inline vector<int> sortId2(const vector<T>& v)
{
return sortId(sortId(v));
}
//给v排序,v2按照同样的顺序调整,输入{1,3,2}{4,5,6},输出{1,2,3}{4,6,5}
template<typename T, typename T2>
static inline void sortExtend(vector<T>& v, vector<T2>& v2)
{
auto ids = sortId(v);
auto v3 = v, v4 = v2;
for (int i = 0; i < v.size(); i++)v[i] = v3[ids[i]], v2[i] = v4[ids[i]];
}
//2个vector中寻找和为s的对,返回结果的每一行都是[id1,id2]
template<typename T>
static vector<vector<int>> findSum(vector<T>v1, vector<T>v2, T s)
{
vector<vector<int>>ans;
int m = min((long long)(v1.size() * v2.size()), (long long)12345678);
ans.reserve(m);
vector<int>tmp(2);
vector<int>v3 = sortId(v2);
sort(v2.begin(), v2.end(), cmp<T>);
for (int i = 0; i < v1.size(); i++)
{
auto it1 = lower_bound(v2.begin(), v2.end(), s - v1[i]);
auto it2 = upper_bound(v2.begin(), v2.end(), s - v1[i]);
tmp[0] = i;
for (auto j = it1; j < it2; j++)
{
tmp[1] = v3[j - v2.begin()];
ans.push_back(tmp);
}
}
return ans;
}
//vector的字典序比较,v1<v2是true,v1>=v2是false
template<typename T>
static bool cmpVector(const vector<T>& v1, const vector<T>& v2)
{
for (int i = 0; i < v1.size() && i < v2.size(); i++)
{
if (v1[i] != v2[i])return v1[i] < v2[i];
}
return v1.size() < v2.size();
}
//vector的字典序排序
template<typename T>
static void sortVector(vector<vector<T>>& v)
{
sort(v.begin(), v.end(), cmpVector<T>);
}
private:
template<typename T>
static inline bool cmp(T a, T b)
{
return a < b;
}
static inline bool cmp(string a, string b)
{
return a.length() < b.length();
}
template<typename T, typename T2>
static inline bool cmpPair(pair<T, T2> x, pair<T, T2> y)
{
if (cmp(x.first, y.first))return true;
if (cmp(y.first, x.first))return false;
return cmp(x.second, y.second);
}
template<typename T, typename T2>
static inline bool cmpJustFirst(pair<T, T2> x, pair<T, T2> y)
{
return cmp(x.first, y.first);
}
};
2,测试代码
template<typename T>
static bool IsSame(const T &a, const T &b)
{
return a == b;
}
template<typename T>
static bool IsSame(const vector<T>& v1, const vector<T>& v2)
{
if (v1.size() - v2.size())return false;
for (int i = 0; i < v1.size(); i++)if (!IsSame(v1[i], v2[i]))return false;
return true;
}
template<typename T, typename T2>
static bool IsSame(const pair<T,T2>&p1, const pair<T, T2>&p2)
{
return IsSame(p1.first, p2.first) && IsSame(p1.second, p2.second);
}
#define EXPECT_EQ(a,b) if(!IsSame(a,b)){cout<<"ERROR!!!!!!!!!\n";return false;}
bool testSortWithOrderMatch()
{
vector<int> v{ 1,4,2,5,3 };
auto ans = SortWithOrderMatch(v);
vector<pair<int,int>> v2{ {1,0},{2,2}, {3,4}, {4,1},{5,3} };
EXPECT_EQ(ans, v2);
return true;
}
bool testVectorOpt()
{
vector<int>v{ 1,4,4,1 };
auto vp = Fshr(v, false);
EXPECT_EQ(vp, (vector<pair<int, int>>{make_pair(1, 1), make_pair(4, 2), make_pair(1, 1)}));
vp = Fshr(v, true);
EXPECT_EQ(vp, (vector<pair<int, int>>{make_pair(1, 2), make_pair(4, 2)}));
v = Funshr(vp);
EXPECT_EQ(v, (vector<int>{ 1, 1, 4, 4}));
vector<vector<int>> v2{ v,v };
auto v3 = Fforeach(v2);
EXPECT_EQ(v3.size(), v.size() * v.size());
v = { 1,2,3 };
map<int, vector<int>>options;
options[1] = { 4 }, options[3] = { 5 };
auto v4 = ChangeMeiJu(v, options);
EXPECT_EQ(v4, (vector<vector<int>> { {1, 2, 3}, { 4,2,3 }, { 1,2,5 }, { 4,2,5 } }));
map<int, vector<int>>options2;
options2[1] = { 6 };
options2[2] = { 7 };
v4 = SubMeiJu(v, 3, options2);
EXPECT_EQ(v4, (vector<vector<int>> { {1, 2, 3}, { 1,6,3 }, { 1,2,7 }, { 1,6,7 } }));
v = vector<int>{ 8, 5, 6, 7 };
EXPECT_EQ(SortId(v), (vector<int>{1, 2, 3, 0}));
EXPECT_EQ(SortId2(v), (vector<int>{3, 0, 1, 2}));
//给v排序,v2按照同样的顺序调整,输入,输出{1,2,3}{4,6,5}
vector<int>v5{ 1,3,2 };
vector<int>v6{ 4,5,6 };
SortExtend(v5, v6);
EXPECT_EQ(v5, (vector<int>{ 1, 2, 3 }));
EXPECT_EQ(v6, (vector<int>{ 4, 6, 5 }));
auto v7 = FindSum(v, v, 13);
EXPECT_EQ(int(v7.size()), 4); //85 58 67 76
EXPECT_EQ(CmpVector(v, vector<int>{ 8, 6, 5, 7 }), true);
EXPECT_EQ(CmpVector(v, v), false);
v2 = { {2,3},{1,2} };
SortVector(v2);
EXPECT_EQ(v2, (vector<vector<int>>{ {1, 2}, { 2,3 }}));
return true;
}
int main()
{
if (testSortWithOrderMatch() && testVectorOpt())cout << "test succ!";
return 0;
}
五,vector的计算
1,代码
class VectorCal
{
public:
//2个vector相加
template<typename T>
static vector<T> vecAdd(const vector<T>& v1, const vector<T>& v2)
{
vector<T>v(max(v1.size(), v2.size()));
for (int i = 0; i < v.size(); i++)v[i] = 0;
for (int i = 0; i < v1.size(); i++)v[i] += v1[i];
for (int i = 0; i < v2.size(); i++)v[i] += v2[i];
return v;
}
//枚举2个vector的两数之和
template<typename T>
static vector<T> everySum(vector<T>& v1, vector<T>& v2)
{
vector<T>ans;
ans.resize(v1.size() * v2.size());
int k = 0;
for (int i = 0; i < v1.size(); i++)for (int j = 0; j < v2.size(); j++)ans[k++] = v1[i] + v2[j];
return ans;
}
//判断2个vector(一维或二维)是否全等
template<typename T>
static bool vecIsSame(const vector<T>& v1, const vector<T>& v2)
{
if (v1.size() - v2.size())return false;
for (int i = 0; i < v1.size(); i++)if (v1[i] != v2[i])return false;
return true;
}
template<typename T>
static bool vecIsSame(const vector<vector<T>>& v1, const vector<vector<T>>& v2) {
if (v1.size() - v2.size())return false;
for (int i = 0; i < v1.size(); i++)if (!vecIsSame(v1[i], v2[i]))return false;
return true;
}
//二维数组去掉重复行
template<typename T>
static vector<vector<T>> deleteSameLine(const vector<vector<T>>& v)
{
vector<vector<T>>ans;
ans.reserve(v.size());
for (int i = 0; i < v.size(); i++)
{
bool flag = true;
for (int j = i + 1; flag && j < v.size(); j++)if (vecIsSame(v[i], v[j]))flag = false;
if (flag)ans.push_back(v[i]);
}
return ans;
}
//判断vector中是否含有重复元素
template<typename T>
static bool haveSameData(vector<T> v)// not const
{
sort(v.begin(), v.end());
for (int i = 1; i < v.size(); i++)if (v[i] == v[i - 1])return true;
return false;
}
//删除二维vector中,含有重复元素的行
template<typename T>
static vector<vector<T>> deleteLineWithSameDatas(vector<vector<T>>& v)
{
vector<vector<int>>ans;
ans.reserve(v.size());
for (int i = 0; i < v.size(); i++)
{
if (!haveSameData(v[i]))ans.push_back(v[i]);
}
return ans;
}
//2个vector的卷积
template<typename T>
static vector<T> vecConvolution(vector<T>& v1, vector<T>& v2)
{
vector<T>ans(v1.size() + v2.size() - 1);
for (int i = 0; i < v1.size(); i++)for (int j = 0; j < v2.size(); j++)ans[i + j] += v1[i] * v2[j];
return ans;
}
};
2,测试代码
template<typename T>
static bool IsSame(const T &a, const T &b)
{
return a == b;
}
template<typename T>
static bool IsSame(const vector<T>& v1, const vector<T>& v2)
{
if (v1.size() - v2.size())return false;
for (int i = 0; i < v1.size(); i++)if (!IsSame(v1[i], v2[i]))return false;
return true;
}
template<typename T, typename T2>
static bool IsSame(const pair<T,T2>&p1, const pair<T, T2>&p2)
{
return IsSame(p1.first, p2.first) && IsSame(p1.second, p2.second);
}
#define EXPECT_EQ(a,b) if(!IsSame(a,b)){cout<<"ERROR!!!!!!!!!\n";return false;}
bool testDeleteLineWithSameDatas()
{
vector<vector<int>>v1{ {1,2,3},{3,4,3},{4,5},{5,6} };
vector<vector<int>>v2{ {1,2,3},{4,5},{5,6} };
EXPECT_EQ(DeleteLineWithSameDatas(v1), v2);
return true;
}
bool testVectorCal()
{
vector<int>v1{ 8,5,6,7 }, v2{ 4,5,6,7 };
EXPECT_EQ(VecAdd(v1, v2), (vector<int>{12, 10, 12, 14}));
EXPECT_EQ(EverySum(v1, v2).size(), v1.size() * v2.size());
vector<vector<int>>v3{ v1,v2,v1 };
EXPECT_EQ(HaveSameData(v3), true);
v3 = DeleteSameLine(v3);
EXPECT_EQ(int(v3.size()), 2);
EXPECT_EQ(HaveSameData(v3), false);
EXPECT_EQ(VecIsSame(v1, v2), false);
v2[0] = 8;
EXPECT_EQ(VecIsSame(v1, v2), true);
EXPECT_EQ(VecConvolution(v1, v2).size(), v1.size() + v2.size() - 1);
return true;
}
int main()
{
if (testDeleteLineWithSameDatas() && testVectorCal())cout << "test succ!";
return 0;
}
六,单链表
1,代码
#ifdef LOCAL
struct listtNode {
int val;
listtNode* next;
listtNode(int x) : val(x), next(NULL) {}
};
#define ListNode listtNode
#endif
class LinkList
{
public:
//构建链表
static ListNode* initLinkList(const vector<int>& v)
{
ListNode* head = new ListNode(0);
ListNode* tail = head;
for (auto vi : v)tail = tail->next = new ListNode(vi);
return head->next;
}
//打印链表
static void outLinkList(ListNode* head)
{
while (head) {
cout << head->val << " ";
head = head->next;
}
}
//获取链表长度
static int linkGetLength(ListNode* p)
{
int ans = 0;
while (p)
{
ans++;
p = p->next;
}
return ans;
}
//两个链表的数据是否全等
static bool isSameLinkList(ListNode*p1, ListNode*p2)
{
if (!p1 && !p2)return true;
return p1 && p2 && p1->val == p2->val && isSameLinkList(p1->next, p2->next);
}
//链表反转,返回新的head
static ListNode* linkReverse(ListNode* p)
{
if (p == NULL)return p;
ListNode* q1;
ListNode* q2;
q1 = p->next, p->next = NULL;
while (q1)
{
q2 = q1->next, q1->next = p, p = q1, q1 = q2;
}
return p;
}
//链表中倒数第k个节点
static ListNode* getKthFromEnd(ListNode* head, int k) {
ListNode* p = head;
while (p && k--)p = p->next;
while (p)p = p->next, head = head->next;
return head;
}
//链表最后一个节点
static ListNode* getTail(ListNode* head)
{
return getKthFromEnd(head,1);
}
//留下前k个节点,把后面的切下来并返回
static ListNode* linkSplit(ListNode* head, int k)
{
while (--k && head) {
head = head->next;
}
if (!head)return head;
auto ans = head->next;
head->next = nullptr;
return ans;
}
//直接合并2个链表
static void linkMerge(ListNode* p1, ListNode* p2)
{
getTail(p1)->next = p2;
}
//把两个链表交叉合并为一个链表
static ListNode* mergeTwoLists(ListNode* p, ListNode* q) {
if (!p)return q;
if (!q)return p;
ListNode* pnext, * qnext, * ans = p;
while (p && q)
{
if (p->next == NULL && q->next != NULL)
{
p->next = q;
break;
}
pnext = p->next, qnext = q->next;
p->next = q, q->next = pnext;
p = pnext, q = qnext;
}
return ans;
}
//把两个升序的链表合并为一个升序的链表
static ListNode* mergeTwoUpLists(ListNode* p, ListNode* q) {
if (!p)return q;
if (!q)return p;
ListNode* head;
if (p->val < q->val)head = p, p = p->next;
else head = q, q = q->next;
ListNode* ans = head;
while (p && q)
{
if (p->val < q->val)ans->next = p, ans = p, p = p->next;
else ans->next = q, ans = q, q = q->next;
}
if (p)ans->next = p;
else ans->next = q;
return head;
}
//把链表转化成结构体指针数组
static vector<ListNode*> listToVec(ListNode* head)
{
vector<ListNode*>ans;
while (head)
{
ans.push_back(head);
head = head->next;
}
return ans;
}
//把结构体指针数组转化成链表
static ListNode* vecToList(vector<ListNode*>v)
{
if (v.empty())return NULL;
for (int i = 0; i < v.size() - 1; i++)v[i]->next = v[i + 1];
v[v.size() - 1]->next = NULL;
return v[0];
}
//链表排序
static ListNode* sortLinkList(ListNode* head)
{
vector<ListNode*>v = listToVec(head);
sort(v.begin(), v.end(), cmp);
return vecToList(v);
}
//判断链表是否有环,有环返回环中任意节点,没环返回NULL
static ListNode* getAnyoneInCycle(ListNode* head) {
if (!head)return NULL;
ListNode* p1 = head, * p2 = head->next;
while (p1 != p2)
{
if (!p1)return NULL;
p1 = p1->next;
if (!p2)return NULL;
p2 = p2->next;
if (!p2)return NULL;
p2 = p2->next;
}
return p1;
}
//求链表环的长度,没环返回0
static int getCycleLen(ListNode* head) {
ListNode* p = getAnyoneInCycle(head);
if (!p)return 0;
ListNode* q = p->next;
int ans = 1;
while (q != p)q = q->next, ans++;
return ans;
}
//求链表环的第一个节点,没环返回NULL
static ListNode* getFirstInCycle(ListNode* head) {
int len = getCycleLen(head);
if (len == 0)return NULL;
ListNode* p = head;
while (len--)p = p->next;
while (head != p)head = head->next, p = p->next;
return p;
}
private:
static bool cmp(ListNode*& a, ListNode*& b)
{
return a->val < b->val;
}
};
2,测试代码
template<typename T>
static bool IsSame(const T &a, const T &b)
{
return a == b;
}
template<typename T>
static bool IsSame(const vector<T>& v1, const vector<T>& v2)
{
if (v1.size() - v2.size())return false;
for (int i = 0; i < v1.size(); i++)if (!IsSame(v1[i], v2[i]))return false;
return true;
}
template<typename T, typename T2>
static bool IsSame(const pair<T,T2>&p1, const pair<T, T2>&p2)
{
return IsSame(p1.first, p2.first) && IsSame(p1.second, p2.second);
}
#define EXPECT_EQ(a,b) if(!IsSame(a,b)){cout<<"ERROR!!!!!!!!!\n";return false;}
#define EXPECT_LINK_EQ(a,b) if(!IsSameLinkList((a),(b))){cout<<"ERROR!!!!!!!!!\n";return false;}
bool testLinkList()
{
vector<int>v{ 1,2,3,4 }, v2{ 4,3,2,1 };
auto p = InitLinkList(v);
//OutLinkList(p);
EXPECT_EQ(LinkGetLength(p), int(v.size()));
auto p2 = LinkReverse(InitLinkList(v2));
EXPECT_LINK_EQ(p, p2);
auto p3 = GetKthFromEnd(p, 3);
EXPECT_EQ(p3->val, 2);
EXPECT_EQ(GetTail(p)->val, 4);
EXPECT_EQ(LinkGetLength(p), 4);
p3 = LinkSplit(p, 3); //留下前k个节点,把后面的切下来并返回
EXPECT_EQ(LinkGetLength(p), 3);
EXPECT_EQ(LinkGetLength(p3), 1);
LinkMerge(p, p3);
EXPECT_LINK_EQ(p, p2);
p2->val = 5;
EXPECT_LINK_EQ(MergeTwoLists(p, p2), InitLinkList(vector<int>{1, 5, 2, 2, 3, 3, 4, 4}));
p = InitLinkList(vector<int>{ 1, 2, 3, 4 });
p2 = InitLinkList(vector<int>{ 0, 2, 3, 4 });
EXPECT_LINK_EQ(MergeTwoUpLists(p, p2), InitLinkList(vector<int>{0, 1, 2, 2, 3, 3, 4, 4}));
return true;
}
bool testLinkList2()
{
vector<int>v{ 1,2,3,4 };
auto p = InitLinkList(v);
auto p2 = VecToList(ListToVec(p));
EXPECT_LINK_EQ(p, p2);
vector<int>v2{ 3,4,1,2 };
p2 = SortLinkList(InitLinkList(v2));
EXPECT_LINK_EQ(p, p2);
p->next->next->next->next = p->next;//1 2 3 4 2
EXPECT_EQ(GetAnyoneInCycle(p)->val >= 2, true);
EXPECT_EQ(GetCycleLen(p), 3);
EXPECT_EQ(GetFirstInCycle(p)->val, 2);
return true;
}
int main()
{
if (testLinkList() && testLinkList2())cout << "test succ!";
return 0;
}
七,双向循环链表
1,代码
struct DeListNode {
int val;
DeListNode* left;
DeListNode* right;
DeListNode() {}
DeListNode(int _val) {
val = _val;
left = NULL;
right = NULL;
}
DeListNode(int _val, DeListNode* _left, DeListNode* _right) {
val = _val;
left = _left;
right = _right;
}
};
class DeLinkList
{
public:
//创建单节点双向循环链表
static DeListNode* getSingleDeList(int val = 0)
{
DeListNode* p = new DeListNode();
p->left = p, p->right = p, p->val = val;
return p;
}
//合并双向循环链表
static void mergeDelist(DeListNode* p1, DeListNode* p2)
{
if (!p1 || !p2)return;
p1->left->right = p2, p2->left->right = p1;
DeListNode* tmp = p2->left;
p2->left = p1->left;
p1->left = tmp;
}
//获取链表长度
static int getLengthOfDeLL(DeListNode* p)
{
int ans = 1;
auto head = p;
p = p->right;
while (p != head)
{
ans++;
p = p->right;
}
return ans;
}
};
2,测试代码
template<typename T>
static bool IsSame(const T &a, const T &b)
{
return a == b;
}
template<typename T>
static bool IsSame(const vector<T>& v1, const vector<T>& v2)
{
if (v1.size() - v2.size())return false;
for (int i = 0; i < v1.size(); i++)if (!IsSame(v1[i], v2[i]))return false;
return true;
}
template<typename T, typename T2>
static bool IsSame(const pair<T,T2>&p1, const pair<T, T2>&p2)
{
return IsSame(p1.first, p2.first) && IsSame(p1.second, p2.second);
}
#define EXPECT_EQ(a,b) if(!IsSame(a,b)){cout<<"ERROR!!!!!!!!!\n";return false;}
bool testDeLinkList()
{
auto p = GetSingleDeList(1);
auto p2 = GetSingleDeList(2);
EXPECT_EQ(GetLengthOfDeLL(p), 1);
MergeDelist(p, p2);
EXPECT_EQ(GetLengthOfDeLL(p), 2);
return true;
}
int main()
{
if (testDeLinkList())cout << "test succ!";
return 0;
}
八,STL操作封装、拓展数据结构
1,代码
class StlBasicOpt
{
public:
//获取列表某处的值
template<typename T>
static T vecGet(const vector<T>& v, int id)
{
return (id >= 0 && id < v.size()) ? v[id] : T{};
}
//id处覆盖或者添加一个数
template<typename T>
static void finsert(vector<T>& v, int id, T x)
{
if (id<0 || id>v.size())return;
if (id == v.size())v.push_back(x);
v[id] = x;
}
//multi***容器x删除一个数值n
template<typename T, typename T2>
static void delOnlyOne(T& x, T2 n)
{
auto it = x.find(n);
if (it != x.end())x.erase(it);
}
//删除最后一个元素
template<typename T>
static void delEnd(T& x)
{
x.erase(--(x.end()));
}
};
//栈的拓展,支持获取最值,所有接口时间复杂度都是 O(1)
class MinMaxStack {
public:
MinMaxStack(int type) { //0最小栈 1最大栈
this->type = type;
}
void push(int x) {//入栈
s.push(x);
if (m.empty() || (type ? (m.top() <= x) : (m.top() >= x)))m.push(x);
}
void pop() {//出栈
if (m.top() == s.top())m.pop();
s.pop();
}
int top() {//获取栈顶
return s.top();
}
int minMax() {//获取最值
return m.top();
}
private:
stack<int>s;//主栈
stack<int>m;//单调栈
int type;
};
//栈的拓展,支持删除最值,所有接口时间复杂度都在 O(log n)之内
class MinMaxStack2 : public StlBasicOpt
{
public:
MinMaxStack2(int type) {//0最小栈 1最大栈
this->type = type;
}
int peekMinMax() { //获取最值
while (m.rbegin()->second.empty())delEnd(m);
return m.rbegin()->first;
}
int popMinMax() { //获取最值并删除
int t = peekMinMax();
m2[t].insert(*(m[t].rbegin()));
delEnd(m[t]);
return t;
}
void push(int t) {
v.push_back(t);
int num = 0;
if (!m[t].empty())num = max(num, *(m[t].rbegin()));
if (!m2[t].empty())num = max(num, *(m2[t].rbegin()));
m[t].insert(num + 1);
}
int pop() {
int t = top();
delEnd(m[t]);
delEnd(v);
return t;
}
int top() {
while (true) {
int t = v.back();
if (m2[t].empty())break;
if (!m[t].empty()) {
if (type ? (*(m[t].rbegin()) > *(m2[t].rbegin())) : (*(m[t].rbegin()) < *(m2[t].rbegin())))break;
}
delEnd(m2[t]);
delEnd(v);
}
return v.back();
}
private:
map<int, set<int>>m;//现存列表
map<int, set<int>>m2;//删除列表
vector<int>v;
int type;
};
//队列的拓展,支持获取最值,所有接口的均摊时间复杂度都是O(1)
class MinMaxQueue : public StlBasicOpt
{
public:
MinMaxQueue(int type) { //0最小队列 1最大队列
this->type = type, vlen = 0;
}
int max_value() {
if (q.empty())return error;
return v[0];
}
void push_back(int value) {
q.push(value);
bool flag = true;
for (int i = vlen; flag && i > 0; i--)
{
if (type ? (value <= v[i - 1]) : (value >= v[i - 1]))
{
finsert(v, i, value);
vlen = i + 1;
flag = false;
}
}
if (flag)
{
finsert(v, 0, value);
vlen = 1;
}
}
int pop_front() {
if (q.empty())return error;
int ans = q.front();
q.pop();
if (v[0] == ans)
{
v.erase(v.begin());
vlen--;
}
return ans;
}
private:
queue<int>q;
vector<int>v;
int type;
int vlen;
int error = -1;
};
template<typename T>
class QueueWithNoSameData //不含重复元素的队列
{
public:
void push(T x) {
if (m[x] == 0)q.push(x), m[x] = 1;
}
void pop() {
m[q.front()] = 0;
q.pop();
}
T front() {
return q.front();
}
bool empty() {
return q.empty();
}
private:
queue<T>q;
map<T, int>m;
};
2,测试代码
template<typename T>
static bool IsSame(const T &a, const T &b)
{
return a == b;
}
template<typename T>
static bool IsSame(const vector<T>& v1, const vector<T>& v2)
{
if (v1.size() - v2.size())return false;
for (int i = 0; i < v1.size(); i++)if (!IsSame(v1[i], v2[i]))return false;
return true;
}
template<typename T, typename T2>
static bool IsSame(const pair<T,T2>&p1, const pair<T, T2>&p2)
{
return IsSame(p1.first, p2.first) && IsSame(p1.second, p2.second);
}
#define EXPECT_EQ(a,b) if(!IsSame(a,b)){cout<<"ERROR!!!!!!!!!\n";return false;}
bool testStlBasicOpt()
{
vector<int>v{ 1, 2, 4, 6 };
EXPECT_EQ(VecGet(v, 3), 6);
EXPECT_EQ(VecGet(v, 4), 0);
Finsert(v, 2, 7);
EXPECT_EQ(v, (vector<int>{1, 2, 7, 6}));
Finsert(v, 4, 7);
EXPECT_EQ(v, (vector<int>{1, 2, 7, 6, 7}));
multiset<int>s{ 1, 2, 3, 2, 4 };
EXPECT_EQ(int(s.size()), 5);
DelOnlyOne(s, 2);
DelEnd(s);
EXPECT_EQ(int(s.size()), 3);
return true;
}
bool testMinStack()
{
MinMaxStack s(0);
s.push(3);
s.push(1);
s.push(2);
EXPECT_EQ(s.top(), 2);
EXPECT_EQ(s.minMax(), 1);
s.pop();
EXPECT_EQ(s.top(), 1);
return true;
}
bool testMaxStack()
{
MinMaxStack2 s(1);
s.push(1);
s.push(3);
s.push(2);
EXPECT_EQ(s.top(), 2);
EXPECT_EQ(s.peekMinMax(), 3);
EXPECT_EQ(s.popMinMax(), 3);
EXPECT_EQ(s.popMinMax(), 2);
return true;
}
bool testMaxQueue()
{
MinMaxQueue q(1);
q.push_back(1);
q.push_back(2);
q.push_back(1);
q.push_back(2);
q.pop_front();
EXPECT_EQ(q.max_value(), 2);
return true;
}
bool testQueueWithNoSameData()
{
QueueWithNoSameData<int>q;
q.push(1);
q.push(2);
q.push(1);
EXPECT_EQ(q.front(), 1);
q.pop();
EXPECT_EQ(q.front(), 2);
q.pop();
EXPECT_EQ(q.empty(), true);
}
int main()
{
if (testStlBasicOpt() && testMinStack() && testMaxStack() && testMaxQueue() && testQueueWithNoSameData())cout << "test succ!";
return 0;
}
九,单调栈、单调队列、背包
1,代码
//单调栈
class MonotonicStack {
public:
MonotonicStack(int type, bool force) { //0递减栈,栈顶最小,1递增栈,栈顶最大, force表示是否是强制单调栈
this->type = type, this->force = force;
}
void push(int x) {
if (force) {
while (!s.empty() && (type ? (s.top() > x) : (s.top() < x)))s.pop();
s.push(x);
}
else {
if (s.empty() || (type ? (s.top() <= x) : (s.top() >= x)))s.push(x);
}
}
void pop() {
if (!s.empty())s.pop();
}
int top() {
return s.top();
}
int size() {
return s.size();
}
private:
stack<int>s;
int type;
bool force;
};
//单调队列
class MonotonicQueue {
public:
MonotonicQueue(int type) { //0递增队列,队首最小,1递减队列,队首最大
this->type = type;
id = 0;
}
void push_back(int x) {
while (!q.empty() && (type ? (m[q.back()] < x) : (m[q.back()] > x)))q.pop_back();
q.push_back(id);
m[id++] = x;
}
void pop_front() {
if (!q.empty())q.pop_front();
}
void pop_back() {
if (!q.empty())q.pop_back();
}
int frontId() {
return q.front();
}
int front() {
return m[q.front()];
}
int tailId() {
return q.back();
}
int size() {
return q.size();
}
private:
deque<int>q;
map<int, int>m;
int type, id;
};
//01背包、完全背包、多重背包、混合背包
class Pack {
public:
//01背包,输入总体积,每个物品的体积和得分,输出最高总得分
static int pack01(int v, const vector<int>& volume, const vector<int>& score) {
vector<int>ans(v + 1, 0);
for (int i = 0; i < volume.size(); i++)pack01Opt(v, volume[i], score[i], ans);
return ans[v];
}
//0-1增强代价背包,需要有volumePlus大小的空间,才能放入volume大小的物品,输出最高总得分
static int packPlus(int v, const vector<int>& volumePlus, const vector<int>& volume, const vector<int>& score) {
vector<node>vec = transPackPlusToNodes(volumePlus, volume, score);
vector<int>ans(v + 1, 0);
for (int i = 0; i < vec.size(); i++) {
for (int j = v; j >= vec[i].vp; j--) {
ans[j] = max(ans[j], ans[j - vec[i].v] + vec[i].s);
}
}
return ans[v];
}
//0-1双得分背包,每个物品有2个得分,输出score的最高总得分,以及在该得分前提下,score2的最高总得分,score2可以为负
static vector<int> packDoubleScore(int v, const vector<int>& volume, const vector<int>& score, const vector<int>& score2) {
vector<int>ans(v + 1, 0), ans2(v + 1, 0);
for (int i = 0; i < volume.size(); i++) {
for (int j = v; j >= volume[i]; j--) {
int j2 = j - volume[i];
if (ans[j] < ans[j2] + score[i])ans[j] = ans[j2] + score[i], ans2[j] = ans2[j2] + score2[i];
else if (ans[j] == ans[j2] + score[i] && ans2[j] < ans2[j2] + score2[i])ans2[j] = ans2[j2] + score2[i];
}
}
return vector<int>{ans[v], ans2[v]};
}
//01背包组合计数,输入总体积,每个物品的体积,输出刚好塞满的方案数,不区分顺序
static int pack01Num(int v, const vector<int>& volume) {
vector<int>ans(v + 1, 0);
ans[0] = 1;
for (int i = 0; i < volume.size(); i++) {
for (int j = v; j >= volume[i]; j--) {
ans[j] += ans[j - volume[i]];
}
}
return ans[v];
}
//完全背包,输入总体积,每个物品的体积和得分,输出最高总得分
static int packComplete(int v, const vector<int>& volume, const vector<int>& score) {
vector<int>ans(v + 1, 0);
for (int i = 0; i < volume.size(); i++)pack01Opt(v, volume[i], score[i], ans);
return ans[v];
}
//完全增强代价背包,需要有volumePlus大小的空间,才能放入volume大小的物品,输出最高总得分
static int packCompletePlus(int v, const vector<int>& volumePlus, const vector<int>& volume, const vector<int>& score) {
vector<node>vec = transPackPlusToNodes(volumePlus, volume, score);
vector<int>ans(v + 1, 0);
for (int i = 0; i < vec.size(); i++) {
for (int j = vec[i].vp; j <= v; j++) {
ans[j] = max(ans[j], ans[j - vec[i].v] + vec[i].s);
}
}
return ans[v];
}
//完全双得分背包,每个物品有2个得分,输出score的最高总得分,以及在该得分前提下,score2的最高总得分,score2可以为负
static vector<int> packCompleteDoubleScore(int v, const vector<int>& volume, const vector<int>& score, const vector<int>& score2) {
vector<int>ans(v + 1, 0), ans2(v + 1, 0);
for (int i = 0; i < volume.size(); i++) {
for (int j = volume[i]; j <= v; j++) {
int j2 = j - volume[i];
if (ans[j] < ans[j2] + score[i])ans[j] = ans[j2] + score[i], ans2[j] = ans2[j2] + score2[i];
else if (ans[j] == ans[j2] + score[i] && ans2[j] < ans2[j2] + score2[i])ans2[j] = ans2[j2] + score2[i];
}
}
return vector<int>{ans[v], ans2[v]};
}
//完全背包组合计数,输入总体积,每个物品的体积,输出刚好塞满的方案数,不区分顺序
static int packCompleteNum(int v, const vector<int>& volume) {
vector<int>ans(v + 1, 0);
ans[0] = 1;
for (int i = 0; i < volume.size(); i++) {
for (int j = volume[i]; j <= v; j++) {
ans[j] += ans[j - volume[i]];
}
}
return ans[v];
}
//完全背包排列计数,输入总体积,每个物品的体积,输出刚好塞满的方案数,区分顺序
static long long packCompleteNumA(int v, const vector<int>& volume, long long p = UINT_MAX) {
vector<long long>ans(v + 1, 0);
ans[0] = 1;
for (int j = 0; j <= v; j++) {
for (int i = 0; i < volume.size(); i++) {
if (j >= volume[i])ans[j] = (ans[j] + ans[j - volume[i]]) % p;
}
}
return ans[v];
}
//多重背包,输入总体积,每个物品的体积和数量和得分,输出最高总得分
static int packMulti(int v, const vector<int>& volume, const vector<int>& num, const vector<int>& score) {
vector<int>ans(v + 1, 0);
for (int i = 0; i < volume.size(); i++)packMultiOpt(v, volume[i], num[i], score[i], ans);
return ans[v];
}
//01、完全、多重的混合背包,num=1是01背包,num=-1是完全背包,num>1是多重背包
static int packMix(int v, const vector<int>& volume, const vector<int>& num, const vector<int>& score) {
vector<int>ans(v + 1, 0);
for (int i = 0; i < volume.size(); i++) {
if (num[i] == 1)pack01Opt(v, volume[i], score[i], ans);
if (num[i] == -1)packCompleteOpt(v, volume[i], score[i], ans);
if (num[i] > 1)packMultiOpt(v, volume[i], num[i], score[i], ans);
}
return ans[v];
}
private:
struct node
{
int vp, v, s;
static bool cmp(node a, node b)
{
return a.vp - a.v < b.vp - b.v;
}
};
static vector<node> transPackPlusToNodes(const vector<int>& volumePlus, const vector<int>& volume, const vector<int>& score)
{
vector<node>vec;
for (int i = 0; i < volumePlus.size(); i++) {
vec.push_back({ volumePlus[i],volume[i],score[i] });
}
sort(vec.begin(), vec.end(), node::cmp);
return vec;
}
static inline void pack01Opt(int v, int volumei, int scorei, vector<int>& ans) {
for (int j = v; j >= volumei; j--) {
ans[j] = max(ans[j], ans[j - volumei] + scorei);
}
}
static inline void packCompleteOpt(int v, int volumei, int scorei, vector<int>& ans) {
for (int j = volumei; j <= v; j++) {
ans[j] = max(ans[j], ans[j - volumei] + scorei);
}
}
static inline void packMultiOpt(int v, int volumei, int numi, int scorei, vector<int>& ans) {
for (int j = 0; j < volumei; j++) {
MonotonicQueue q(1);
for (int k = j; k <= v; k += volumei) {
q.push_back(ans[k] - k / volumei * scorei);
ans[k] = k / volumei * scorei + q.front();
if (q.tailId() - numi == q.frontId())q.pop_front();
}
}
}
};
//双代价背包
class PackDoubleVolume {
public:
//0-1双代价背包,每个物品有2个代价,输出最高总得分
static int pack01(int v, int v2, const vector<int>& volume, const vector<int>& volume2, const vector<int>& score) {
vector<vector<int>>ans(v + 1, vector<int>(v2 + 1, 0));
for (int i = 0; i < volume.size(); i++)pack01Opt(v, v2, volume[i], volume2[i], score[i], ans);
return ans[v][v2];
}
//完全双代价背包,每个物品有2个代价,输出最高总得分
static int packComplete(int v, int v2, const vector<int>& volume, const vector<int>& volume2, const vector<int>& score) {
vector<vector<int>>ans(v + 1, vector<int>(v2 + 1, 0));
for (int i = 0; i < volume.size(); i++)packCompleteOpt(v, v2, volume[i], volume2[i], score[i], ans);
return ans[v][v2];
}
//多重双代价背包,每个物品有2个代价,输出最高总得分
static int packMulti(int v, int v2, const vector<int>& volume, const vector<int>& volume2, const vector<int>& num, const vector<int>& score) {
vector<vector<int>>ans(v + 1, vector<int>(v2 + 1, 0));
for (int i = 0; i < volume.size(); i++) packMultiOpt(v, v2, volume[i], volume2[i], num[i], score[i], ans);
return ans[v][v2];
}
//01、完全、多重的混合双代价背包,num=1是01背包,num=-1是完全背包,num>1是多重背包
static int packMix(int v, int v2, const vector<int>& volume, const vector<int>& volume2, const vector<int>& num, const vector<int>& score) {
vector<vector<int>>ans(v + 1, vector<int>(v2 + 1, 0));
for (int i = 0; i < volume.size(); i++) {
if (num[i] == 1)pack01Opt(v, v2, volume[i], volume2[i], score[i], ans);
if (num[i] == -1)packCompleteOpt(v, v2, volume[i], volume2[i], score[i], ans);
if (num[i] > 1)packMultiOpt(v, v2, volume[i], volume2[i], num[i], score[i], ans);
}
return ans[v][v2];
}
private:
static inline void pack01Opt(int v, int v2, int volumei, int volume2i, int scorei, vector<vector<int>>& ans) {
for (int j = v; j >= volumei; j--) {
for (int j2 = v2; j2 >= volume2i; j2--) {
ans[j][j2] = max(ans[j][j2], ans[j - volumei][j2 - volume2i] + scorei);
}
}
}
static inline void packCompleteOpt(int v, int v2, int volumei, int volume2i, int scorei, vector<vector<int>>& ans) {
for (int j = volumei; j <= v; j++) {
for (int j2 = volume2i; j2 <= v2; j2++) {
ans[j][j2] = max(ans[j][j2], ans[j - volumei][j2 - volume2i] + scorei);
}
}
}
static inline void packMultiOpt(int v, int v2, int volumei, int volume2i, int numi, int scorei, vector<vector<int>>& ans) {
for (int j = 0; j <= v; j++) {
for (int j2 = 0; j2 <= (j < volumei ? v2 : volume2i - 1); j2++) {
MonotonicQueue q(1);
for (int k = j, k2 = j2; k <= v, k2 <= v2; k += volumei, k2 += volume2i) {
q.push_back(ans[k][k2] - k / volumei * scorei);
ans[k][k2] = k / volumei * scorei + q.front();
if (k / volumei - numi == q.frontId())q.pop_front();
}
}
}
}
};
//分组背包
class PackGroup {
public:
//分组背包,输入总体积,每组每个物品的体积和得分,输出最高总得分
static int packGroup01(int v, const vector<vector<int>>& volume, const vector<vector<int>>& score) {
return packGroup01Ans(v, volume, score)[v];
}
//分组背包组合计数,输入总体积,每组每个物品的体积,输出刚好塞满的方案数,不区分顺序
static int packGroup01Num(int v, const vector<vector<int>>& volume) {
vector<int>ans(v + 1, 0);
for (int i = 0; i < volume.size(); i++) {
for (int j = v; j >= 0; j--) {
for (int k = 0; k < volume[i].size(); k++) {
if (j >= volume[i][k])ans[j] += ans[j - volume[i][k]];
}
}
}
return ans[v];
}
protected:
//分组背包,输入总体积,每组每个物品的体积和得分,输出最高总得分
static vector<int> packGroup01Ans(int v, const vector<vector<int>>& volume, const vector<vector<int>>& score) {
vector<int>ans(v + 1, 0);
for (int i = 0; i < volume.size(); i++) {
for (int j = v; j >= 0; j--) {
for (int k = 0; k < volume[i].size(); k++) {
if (j >= volume[i][k])ans[j] = max(ans[j], ans[j - volume[i][k]] + score[i][k]);
}
}
}
return ans;
}
};
//泛化物品背包
class PackGeneralize :public PackGroup {
public:
//每个物品i都有一个价值函数score[i],拿j个i需要的代价是j,获得的价值是score[i][j]
static int packComplete(int v, const vector<vector<int>>& score) {
return packCompleteAns(v, score)[v];
}
protected:
static vector<int> packCompleteAns(int v, const vector<vector<int>>& score) {
vector<vector<int>> volume2, score2;
for (auto& s : score) {
vector<int>vi, si;
for (int i = 1; i <= v && i<s.size(); i++) {
vi.push_back(i), si.push_back(s[i]);
}
volume2.push_back(vi), score2.push_back(si);
}
return packGroup01Ans(v, volume2, score2);
}
};
//依赖背包(仅限森林)
class PackDepend :public PackGeneralize {
public:
//依赖背包(仅限森林),children是每个节点的子节点集,所有节点编号0到n-1,children和volume和score的长度都为n
static int packDependTrees(int v, const vector<vector<int>>& children, const vector<int>& volume, const vector<int>& score) {
return packDependTrees(v, getRoots(children), children, volume, score)[v];
}
//依赖背包(仅限森林),fas是所有根节点,children是每个节点的子节点集,所有节点编号0到n-1,children和volume和score的长度都为n
static vector<int> packDependTrees(int v, const vector<int>& roots, const vector<vector<int>>& children, const vector<int>& volume, const vector<int>& score) {
vector<vector<int>> score2;
for (auto root : roots) {
score2.push_back(packDependTree(v, root, children, volume, score));
}
return PackGeneralize::packCompleteAns(v, score2);
}
private:
static vector<int> getRoots(const vector<vector<int>>& children) {
map<int, int>m;
for (auto& cs : children)for (auto x : cs)m[x]++;
vector<int>roots;
for (int i = 0; i < children.size(); i++)if (m[i] == 0)roots.push_back(i);
return roots;
}
static vector<int> packDependTree(int v, int root, const vector<vector<int>>& children, const vector<int>& volume, const vector<int>& score) {
vector<int> ans(v + 1, 0);
if (volume[root] > v)return ans;
if (children[root].empty()) {
ans[volume[root]] = score[root];
return ans;
}
return packDependTrees(v - volume[root], children[root], children, volume, score);
}
};
2,测试代码
template<typename T>
static bool IsSame(const T &a, const T &b)
{
return a == b;
}
template<typename T>
static bool IsSame(const vector<T>& v1, const vector<T>& v2)
{
if (v1.size() - v2.size())return false;
for (int i = 0; i < v1.size(); i++)if (!IsSame(v1[i], v2[i]))return false;
return true;
}
template<typename T, typename T2>
static bool IsSame(const pair<T,T2>&p1, const pair<T, T2>&p2)
{
return IsSame(p1.first, p2.first) && IsSame(p1.second, p2.second);
}
#define EXPECT_EQ(a,b) if(!IsSame(a,b)){cout<<"ERROR!!!!!!!!!\n";return false;}
bool testMonotonicStack()
{
MonotonicStack s(0, true);
s.push(3); // 3
s.push(2); // 3 2
EXPECT_EQ(s.top(), 2);
EXPECT_EQ(s.size(), 2);
s.push(4); //先弹出2 再弹出3 再入栈4
EXPECT_EQ(s.top(), 4);
EXPECT_EQ(s.size(), 1);
return true;
}
bool testMonotonicQueue()
{
MonotonicQueue q(0);
q.push_back(2);
q.push_back(1);
q.push_back(3);
EXPECT_EQ(q.front(), 1);
return true;
}
bool testPack()
{
vector<int>volume{ 2,4,5,8 };
vector<int>score{ 3,10,10,18 };
//01背包
EXPECT_EQ(Pack::pack01(9, volume, score), 20);//10+10=20
vector<int>volumePlus{ 3,6,6,8 };
//0-1增强代价背包
EXPECT_EQ(Pack::packPlus(9, volumePlus, volume, score), 18);//18=18
vector<int>score2{ 0,-1,-2,3 };
//0-1双得分背包
EXPECT_EQ(Pack::packDoubleScore(13, volume, score, score2), (vector<int>{28, 2}));//10+18=28,-1+3=2
//01背包组合计数
EXPECT_EQ(Pack::pack01Num(10, vector<int>{2, 2, 3, 3, 5, 6}), 6); //2233 235 235 235 235 226 六种情况
// 以下 待完善
//完全背包
//完全增强代价背包
//完全双得分背包
//完全背包组合计数
//完全背包排列计数
//多重背包
//01、完全、多重的混合背包
return true;
}
bool testPack2()
{
// 以下 待完善
//0-1双代价背包
//完全双代价背包
//多重双代价背包
//01、完全、多重的混合双代价背包
//分组背包
//分组背包组合计数
//泛化物品背包
//依赖背包 * 2
return true;
}
int main()
{
if (testMonotonicStack() && testMonotonicQueue() && testPack() && testPack2())cout << "test succ!";
return 0;
}