diff --git a/C++/面向对象/1 构造函数和析构函数.md b/C++/面向对象/1 构造函数和析构函数.md index 6b9d14ee..44029f89 100644 --- a/C++/面向对象/1 构造函数和析构函数.md +++ b/C++/面向对象/1 构造函数和析构函数.md @@ -1,12 +1,7 @@ # 拷贝控制 -> 目录 -> * 拷贝、赋值与销毁 -> * 拷贝控制和资源管理 -> * 交换操作 -> * 拷贝控制实例 -> * 动态内存管理类 -> * 对象移动 +> 参考文献 +> * [https://www.cnblogs.com/sunchaothu/p/11392116.html](https://www.cnblogs.com/sunchaothu/p/11392116.html) > 类的特殊函数 > * 初始化——构造函数 @@ -14,10 +9,20 @@ > * 移动——移动构造函数 > * 赋值——拷贝赋值运算符、移动赋值运算符 > * 销毁——析构函数 +``` +默认构造(无参)   T() +拷贝构造       T(const T& ) +移动构造       T() + +拷贝赋值       T& operator=(T& ) +移动赋值       T& operator=(T&& ) + +析构         ~T() +``` ## 1 构造函数 -> 与类同名的,没有返回值的函数,用来创建、赋值、移动、销毁该类的对象。 +> 与类同名的,没有返回值的函数,用来创建、拷贝、移动、销毁该类的对象。 ## 1.1 合成构造函数 编译器自动生成的一系列构造函数。包括以下几种 @@ -29,11 +34,11 @@ * 合成析构函数 * 系统自动生成的析构函数。 -## 1.2 默认构造函数 +## 1.2 默认构造函数和普通构造函数 +* 默认构造函数是无参构造函数 +* 普通构造函数是一系列有参数的构造函数。 -无参构造函数。 - -## 1.3 拷贝构造函数 +## 1.3 拷贝构造函数和拷贝赋值运算符 唯一参数是当前类类型,或者当前类型的const引用。 @@ -57,15 +62,88 @@ string nies = string("efji"); * 从一个返回类型为费引用类型的函数返回一个对象 * 用花括号列表初始化一个数组中的元素或一个聚合类中的成员 -### 赋值运算符(拷贝运算符) +### 赋值运算符(拷贝赋值运算符) > 普通赋值的时候,会调用重载的赋值运算符。 * 编译器会自动生成合成拷贝赋值运算符 * 需要重载赋值运算符。 -## 1.4 移动构造函数 +## 1.4 移动构造函数和移动赋值运算符 +* 在面向对象中,有的类是可以拷贝的,例如车、房等他们的属性是可以复制的,可以调用拷贝构造函数,有点类的对象则是独一无二的,或者类的资源是独一无二的,比如 IO 、 std::unique_ptr等,他们不可以复制,但是可以把资源交出所有权给新的对象,称为可以移动的。 +* C++11最重要的一个改进之一就是引入了move语义,这样在一些对象的构造时可以获取到已有的资源(如内存)而不需要通过拷贝,申请新的内存,这样移动而非拷贝将会大幅度提升性能。例如有些右值即将消亡析构,这个时候我们用移动构造函数可以接管他们的资源。 +``` +#include +#include + +using namespace std; + +class A{ +public: + //默认构造函数 + A():i(new int[500]){ + cout<<"class A construct!"< 参考文献 +> * [cnblogs.com/sunchaothu/p/11343517.html](cnblogs.com/sunchaothu/p/11343517.html) + + +> 为了导入右值和移动语义,首先复习了以下临时对象在函数返回值和传参数时构造了几次;然后对比介绍了左值和右值,以及右值引用的形式和含义。为移动语义和完美转发的介绍做铺垫。 +## 1 问题导入 + +C++11 引入了 std::move 语义、右值引用、移动构造和完美转发这些特性。 + + +* 函数返回值是传值的时候发生几次对象构造、几次拷贝? +* 函数的形参是值传递的时候发生几次对象构造? + +### 函数返回值原理 +``` +// main.cpp +#include +using namespace std; + +class A{ +public: + A(){ + cout<<"class A construct!"< 参考文献 +> * [https://www.cnblogs.com/sunchaothu/p/11392116.html](https://www.cnblogs.com/sunchaothu/p/11392116.html) +> * [ +https://stackoverflow.com/questions/3106110/what-are-move-semantics/3109981#3109981]( +https://stackoverflow.com/questions/3106110/what-are-move-semantics/3109981#3109981) + +## 1 可拷贝和可移动的概念 + +* 在面向对象中,有的类是可以拷贝的,例如车、房等他们的属性是可以复制的,可以调用拷贝构造函数和拷贝赋值函数。 +* 有点类的对象则是独一无二的,或者类的资源是独一无二的,比如 IO 、 std::unique_ptr等,他们不可以复制,但是可以把资源交出所有权给新的对象,称为可以移动的,可以调用移动构造函数和移动赋值函数。 +* C++11最重要的一个改进之一就是引入了move语义,这样在一些对象的构造时可以获取到已有的资源(如内存)而不需要通过拷贝,申请新的内存,这样移动而非拷贝将会大幅度提升性能。例如有些右值即将消亡析构,这个时候我们用移动构造函数可以接管他们的资源。 + +## 2 移动构造函数和移动赋值函数 + +```C++ +#include +#include + +using namespace std; + +class A{ +public: + A():i(new int[500]){ + cout<<"class A construct!"< +_NODISCARD constexpr remove_reference_t<_Ty>&& move(_Ty&& _Arg) noexcept { // forward _Arg as movable + return static_cast&&>(_Arg); +} +``` + +可以看到std::move 是一个模板函数,通过remove_reference_t获得模板参数的原本类型,然后把值转换为该类型的右值。用C++大师 Scott Meyers 的在《Effective Modern C++》中的话说, std::move 是个cast ,not a move. + +值得注意的是: 使用move意味着,把一个左值转换为右值,原先的值不应该继续再使用(承诺即将废弃) + +## 4 使用 std::move 实现一个高效的 swap 函数 +我们可以使用 move语义实现一个 交换操作,swap;在不使用 Move 语义的情况下 +``` +swap(A &a1, A &a2){ + A tmp(a1); // 拷贝构造函数一次,涉及大量数据的拷贝 + a1 = a2; // 拷贝赋值函数调用,涉及大量数据的拷贝 + a2 = tmp; // 拷贝赋值函数调用,涉及大量数据的拷贝 +} +``` +如果使用 Move语义,即加上移动构造函数和移动赋值函数: +``` +void swap_A(A &a1, A &a2){ + A tmp(std::move(a1)); // a1 转为右值,移动构造函数调用,低成本 + a1 = std::move(a2); // a2 转为右值,移动赋值函数调用,低成本 + a2 = std::move(tmp); // tmp 转为右值移动给a2 +} +``` +可以看到move语义确实可以提高性能,事实上, move语义广泛地用于标准库的容器中。C++11标准库里的std::swap 也是基于移动语义实现的。 + +说到了 swap, 那就不得不说一下啊 move-and-swap 技术了 + +## 5 Move and swap 技巧 +看下面一段代码,实现了一个 unique_ptr ,和标准的std::unqiue_ptr的含义一致,智能指针的一种。 +```C++ +template +class unique_ptr +{ + T* ptr; + +public: + + + explicit unique_ptr(T* p = nullptr) + { + ptr = p; + } + + ~unique_ptr() + { + delete ptr; + } + + // move constructor + unique_ptr(unique_ptr&& source) // note the rvalue reference + { + ptr = source.ptr; + source.ptr = nullptr; + } + + /* unique_ptr& operator=(unique_ptr&& source) // 这里使用右值引用 + { + if (this != &source) // beware of self-assignment + { + delete ptr; // release the old resource + + ptr = source.ptr; // acquire the new resource + source.ptr = nullptr; + } + return *this; + } */ + + // move and swap idiom replace the move assignment operator + unique_ptr& operator=(unique_ptr rhs) // 这里不用引用,会调用移动构造函数 + { + std::swap(ptr, rhs.ptr); + // std::swap(*this,rhs) // is also ok + return *this; + } + + + + T* operator->() const + { + return ptr; + } + + T& operator*() const + { + return *ptr; + } +}; +``` +在这里如果要按照常规办法写移动赋值函数,函数体内需要写一堆检查自赋值等冗长的代码。使用 move-and-swap语义,只用简短的两行就可以写出来。 在移动赋值函数中 source 是个局部对象,这样在形参传递过来的时候必须要调用拷贝构造函数(这里没有实现则不可调用)或者移动构造函数 +,(事实上仅限右值可以传进来了)。然后 std::swap 负责把原先的资源和source 进行交换,完成了移动赋值。这样写节省了很多代码,很优雅。 + + diff --git a/C++/高级特性/3 C++完美转发.md b/C++/高级特性/3 C++完美转发.md new file mode 100644 index 00000000..a35cec51 --- /dev/null +++ b/C++/高级特性/3 C++完美转发.md @@ -0,0 +1,126 @@ +# 完美转发 + + +## 1 概念 + +首先解释一下什么是完美转发,它指的是函数模板可以将自己的参数“完美”地转发给内部调用的其它函数。所谓完美,即不仅能准确地转发参数的值,还能保证被转发参数的左、右值属性不变。 + +``` +template +void function(T t) { + otherdef(t); +} +``` + +function() 函数模板中调用了 otherdef() 函数。在此基础上,完美转发指的是:如果 function() 函数接收到的参数 t 为左值,那么该函数传递给 otherdef() 的参数 t 也是左值;反之如果 function() 函数接收到的参数 t 为右值,那么传递给 otherdef() 函数的参数 t 也必须为右值。 + + +## 2 C++98实现完美转发 + +* C++98通过左值引用和常量左值引用+函数重载实现完美转发 + +* C++98/03 标准下的 C++ 也可以实现完美转发,只是实现方式比较笨拙。通过前面的学习我们知道,C++ 98/03 标准中只有左值引用,并且可以细分为非 const 引用和 const 引用。其中,使用非 const 引用作为函数模板参数时,只能接收左值,无法接收右值;而 const 左值引用既可以接收左值,也可以接收右值,但考虑到其 const 属性,除非被调用函数的参数也是 const 属性,否则将无法直接传递。 + + +* 如果使用 C++ 98/03 标准下的 C++ 语言,我们可以采用函数模板重载的方式实现完美转发 + + +```C++ +#include +using namespace std; +//重载被调用函数,查看完美转发的效果 +void otherdef(int & t) { + cout << "lvalue\n"; +} +void otherdef(const int & t) { + cout << "rvalue\n"; +} +//重载函数模板,分别接收左值和右值 +//接收右值参数 +template +void function(const T& t) { + otherdef(t); +} +//接收左值参数 +template +void function(T& t) { + otherdef(t); +} +int main() +{ + function(5);//5 是右值 + int x = 1; + function(x);//x 是左值 + return 0; +} +// 程序执行结果为: +// rvalue +// lvalue +``` +从输出结果中可以看到,对于右值 5 来说,它实际调用的参数类型为 const T& 的函数模板,由于 t 为 const 类型,所以 otherdef() 函数实际调用的也是参数用 const 修饰的函数,所以输出“rvalue”;对于左值 x 来说,2 个重载模板函数都适用,C++编译器会选择最适合的参数类型为 T& 的函数模板,进而 therdef() 函数实际调用的是参数类型为非 const 的函数,输出“lvalue”。 + + + +## 3 C++ 11实现完美转发。 + +* C++ 11 标准中允许在函数模板中使用右值引用来实现完美转发 + + +### 万能引用规则 +* C++11 标准中规定,通常情况下右值引用形式的参数只能接收右值,不能接收左值。但对于函数模板中使用右值引用语法定义的参数来说,它不再遵守这一规定,既可以接收右值,也可以接收左值(此时的右值引用又被称为“万能引用”) + + +* 在 C++11 标准中实现完美转发,只需要编写如下一个模板函数即可 +``` +template +void function(T&& t) { + otherdef(t); +} +``` + +### 引用折叠规则 +* 此模板函数的参数 t 既可以接收左值,也可以接收右值。但仅仅使用右值引用作为函数模板的参数是远远不够的,还有一个问题继续解决,即如果调用 function() 函数时为其传递一个左值引用或者右值引用的实参。 + +* C++ 11标准为了更好地实现完美转发,特意为其指定了新的类型匹配规则,又称为引用折叠规则(假设用 A 表示实际传递参数的类型): + * 当实参为左值或者左值引用(A&)时,函数模板中 T&& 将转变为 A&(A& && = A&); + * 当实参为右值或者右值引用(A&&)时,函数模板中 T&& 将转变为 A&&(A&& && = A&&)。 + +``` +int n = 10; +int & num = n; +function(num); // T 为 int& +int && num2 = 11; +function(num2); // T 为 int && +``` +### Foward模板函数 + +* 引入了一个模板函数 forword(),我们只需要调用该函数,将函数模板接收到的形参连同其左、右值属性,一起传递给被调用的函数呢? + +```C++ +#include +using namespace std; +//重载被调用函数,查看完美转发的效果 +void otherdef(int & t) { + cout << "lvalue\n"; +} +void otherdef(const int & t) { + cout << "rvalue\n"; +} +//实现完美转发的函数模板 +template +void function(T&& t) { + otherdef(forward(t)); +} +int main() +{ + function(5); + int x = 1; + function(x); + return 0; +} +// 程序执行结果为: +// rvalue +// lvalue +``` + +* 总的来说,在定义模板函数时,我们采用右值引用的语法格式定义参数类型,由此该函数既可以接收外界传入的左值,也可以接收右值;其次,还需要使用 C++11 标准库提供的 forword() 模板函数修饰被调用函数中需要维持左、右值属性的参数。由此即可轻松实现函数模板中参数的完美转发。 \ No newline at end of file diff --git a/C++/高级特性/3.cpp b/C++/高级特性/3.cpp new file mode 100644 index 00000000..5d7acaa6 --- /dev/null +++ b/C++/高级特性/3.cpp @@ -0,0 +1,27 @@ +#include +using namespace std; +//重载被调用函数,查看完美转发的效果 +void otherdef(int & t) { + cout << "lvalue\n"; +} +void otherdef(const int & t) { + cout << "rvalue\n"; +} +//重载函数模板,分别接收左值和右值 +//接收右值参数。常量左值引用可以接受左值、常量左值、右值、常量右值。 +template +void function(const T& t) { + otherdef(t); +} +//接收左值参数 +template +void function(T& t) { + otherdef(t); +} +int main() +{ + function(5);//5 是右值 + int x = 1; + function(x);//x 是左值 + return 0; +} \ No newline at end of file diff --git a/C++/高级特性/image/2021-07-21-11-45-51.png b/C++/高级特性/image/2021-07-21-11-45-51.png new file mode 100644 index 00000000..db5433b1 Binary files /dev/null and b/C++/高级特性/image/2021-07-21-11-45-51.png differ diff --git a/C++/高级特性/说明.md b/C++/高级特性/说明.md new file mode 100644 index 00000000..e35df5e7 --- /dev/null +++ b/C++/高级特性/说明.md @@ -0,0 +1 @@ +> 主要用来记录 effectiveC++ 和more effective c++中涉及到的基础知识和高级特性。 \ No newline at end of file diff --git a/工作日志/2021年7月18日-今日计划.md b/工作日志/2021年7月18日-今日计划.md index 6dbefa19..cb81e7a7 100644 --- a/工作日志/2021年7月18日-今日计划.md +++ b/工作日志/2021年7月18日-今日计划.md @@ -3,25 +3,12 @@ * 十篇文章(2021.04文件夹下的内容) * [x] FedFMC * [x] EWC(FedFMC中用到的一种终身学习的方法,需要了解,作为参考文献)是一种增量学习方案 - * [ ] Overcoming Forgetting in Federated Learning on Non-IID Data 利用增量学习方案解决联邦学习中非独立同分布问题的另外一个方法。 - * [ ] Federated Meta-Learning for Fraudulent Credit Card Detection 联邦元学习解决信用卡诈骗检测 + * [x] Overcoming Forgetting in Federated Learning on Non-IID Data 利用增量学习方案解决联邦学习中非独立同分布问题的另外一个方法。 + * [x] Federated Meta-Learning for Fraudulent Credit Card Detection 联邦元学习解决信用卡诈骗检测 * [x] Learning Classifiers When the Training Data Is Not IID - * [ ] on the convergence of fl on noniid data + * [x] on the convergence of fl on noniid data * [x] federated learning with non iid data - * [ ] federated learning on non iid data silos an experiment - * [ ] federated learning with non iid data : a survey - * [ ] fedAT - * [ ] Android Malware Detection using Deep Learning on API Method Sequences - * [ ] LoAdaBoost: loss-based AdaBoost federated machine learning with reduced computational complexity on IID and non-IID intensive care data - * [ ] A scalable and extensible framework for android malware detection and family attribution - * [ ] CTDroid: Leveraging a Corpus of Technical Blogs for Android Malware Analysis - * [ ] Optimizing symbolic execution for malware behavior classification - * [ ] Cross-Gradient Aggregation for Decentralized Learning from Non-IID data - * [ ] Federated Learning on Non-IID Data Silos: An Experimental Study - * [ ] JOWMDroid: Android malware detection based on feature weighting with joint optimization of weight-mapping and classifier parameters - * [ ] Inverse Distance Aggregation for Federated Learning with Non-IID Data - * [ ] DAMBA: Detecting Android Malware by ORGB Analysis - * [ ] DeepIntent: Deep Icon-Behavior Learning for Detecting Intention-Behavior Discrepancy in Mobile Apps + * [x] federated learning with non iid data : a survey ## 总结 diff --git a/工作日志/2021年7月21日-今日计划.md b/工作日志/2021年7月21日-今日计划.md new file mode 100644 index 00000000..1b4cc44e --- /dev/null +++ b/工作日志/2021年7月21日-今日计划.md @@ -0,0 +1,8 @@ +## 计划 + +### 毕设——论文阅读2.00-6.00 +* [x] federated learning on non iid data silos an experiment +* [x] fedAT +* [x] 自适应联邦学习算法 + +## 总结 \ No newline at end of file diff --git a/工作日志/2021年7月22日-今日计划.md b/工作日志/2021年7月22日-今日计划.md new file mode 100644 index 00000000..34b63c39 --- /dev/null +++ b/工作日志/2021年7月22日-今日计划.md @@ -0,0 +1,18 @@ +## 计划 + +### 毕设——论文阅读2.00-6.00 +* [x] mocha 联邦多任务学习 +* [x] Improving Federated Learning Personalization via Model Agnostic Meta Learning +* [x] Personalized Federated Learning for Intelligent IoT Applications: A Cloud-Edge Based Framework +* [x] Personalized Federated Learning With Differential Privacy +* [x] Personalized Federated Learning with Moreau Envelopes +* [x] Personalized Federated Learning: A Meta-Learning Approach +* [x] Salvaging Federated Learning by Local Adaptation +* [x] Survey of Personalization Techniques for Federated Learning + + + +## 总结 + + +* 基本把非独立同分布问题的经典方法看完了。接下来进行复现。尝试对各种方法进行对比,主要是基于手写体数据集构建非独立同分布的实验。然后将数据集更改为自己的数据集(等选择好数据集之后,将数据及进行更换。) \ No newline at end of file diff --git a/工作日志/2021年7月23日-今日计划.md b/工作日志/2021年7月23日-今日计划.md new file mode 100644 index 00000000..f364b056 --- /dev/null +++ b/工作日志/2021年7月23日-今日计划.md @@ -0,0 +1,23 @@ +## 计划 + +### 毕设——论文阅读2.00-6.00 + +* [x] Android Malware Detection using Deep Learning on API Method Sequences +* [x] LoAdaBoost: loss-based AdaBoost federated machine learning with reduced computational complexity on IID and non-IID intensive care data +* [x] A scalable and extensible framework for android malware detection and family attribution +* [x] CTDroid: Leveraging a Corpus of Technical Blogs for Android Malware Analysis +* [x] Optimizing symbolic execution for malware behavior classification +* [x] Cross-Gradient Aggregation for Decentralized Learning from Non-IID data +* [x] JOWMDroid: Android malware detection based on feature weighting with joint optimization of weight-mapping and classifier parameters +* [x] DAMBA: Detecting Android Malware by ORGB Analysis +* [x] DeepIntent: Deep Icon-Behavior Learning for Detecting Intention-Behavior Discrepancy in Mobile Apps + + +### 就业 + +- [x] LeetCode一道困难题。10.00-12.00 +- [ ] C++基础知识看完。8.00-10.00 + + + +## 总结 \ No newline at end of file diff --git a/工作日志/2021年7月9日-七月份安排.md b/工作日志/2021年7月9日-七月份安排.md index 56289942..2be9462e 100644 --- a/工作日志/2021年7月9日-七月份安排.md +++ b/工作日志/2021年7月9日-七月份安排.md @@ -2,13 +2,16 @@ ## 任务 ### 毕设 * 阅读论文(两周)7.16-7.25(每天十篇可能读完!!!) - * 恶意软件相关的论文 - * 联邦学习相关的论文 - * 非独立同分布和半监督学习相关的文章 -* 完成实验(三周)(7.25-8.8) - * 特征提取的实验 - * 联邦学习针对非独立同分布的实验 - * 联邦半监督学习的实验 + * 恶意软件相关的论文(7.30) + * 联邦学习相关的论文(7.25) + * 非独立同分布相关的文章(7.30) + * ~~联邦半监督学习的文章(这一个点确实可以去掉了)~~ +* 完成实验(四周)(7.25-8.8) + * 联邦学习针对非独立同分布(手写体数据实验实现)的实验(一周) + * 恶意软件特征提取的实验(一周) 什么样的数据集?怎样的方法提取特征?提取哪些特征用于实验?使用什么样的模型? + * 联邦学习针对恶意软件数据集的实验。(一周) + * 差分隐私应用的实验(一周) + * ~~联邦半监督学习的实验~~ * 完成小论文(三周) * 一篇关于非独立同分布联邦学习的小实验 * 完成大论文(四周) diff --git a/工作日志/毕业设计.md b/工作日志/毕业设计.md index 541e9eff..3ad8313b 100644 --- a/工作日志/毕业设计.md +++ b/工作日志/毕业设计.md @@ -55,9 +55,14 @@ 2. 联邦半监督学习方案——半监督方案? 3. 联邦非独立同分布学习方案——某一个方案 -论文贡献 -1. 实现以上方法 -2. 实现了仿真系统和实验验证 +论文贡献(到时候再展开或者压缩内容。) +1. 实现了差分隐私,并通过实验验证了差分隐私对参数隐私的保护 +2. ~~实现了半监督学习方案。这个可以去掉,如果最后实现起来比较简单,则可以加上~~ +3. 使用了联邦元学习解决了非独立同分布问题 +4. 一个恶意软件特征提取和分析工具 +5. 完成了相关的实验验证。证明了balabala +6. 构建了联邦学习框架和恶意软件检测系统。能够使用半监督学习,差分隐私保护用户的隐私,能够针对非独立同分布场景,训练机器学习模型。恶意软件检测系统包括特征提取模块和模型检测模块。 +7. 提供了一个训练框架,以及一个可用的模型。 ### 论文结构 diff --git a/算法/A类:基本算法/5 动态规划——线性动态规划.md b/算法/A类:基本算法/5 动态规划——线性动态规划.md index 18458bee..7eb3ec8a 100644 --- a/算法/A类:基本算法/5 动态规划——线性动态规划.md +++ b/算法/A类:基本算法/5 动态规划——线性动态规划.md @@ -121,7 +121,7 @@ public int climbStairs(int n) { ### 算法设计 -* **状态定义**: 设动态规划列表 dpdp ,dp[i]dp[i] 代表以元素 nums[i]nums[i] 为结尾的连续子数组最大和。 +* **状态定义**: 设动态规划列表 dp ,dp[i]dp[i] 代表以元素 nums[i]nums[i] 为结尾的连续子数组最大和。 * 为何定义最大和 dp[i]dp[i] 中必须包含元素 nums[i]nums[i] :保证 dp[i]dp[i] 递推到 dp[i+1]dp[i+1] 的正确性;如果不包含 nums[i]nums[i] ,递推时则不满足题目的 连续子数组 要求。 * **转移方程**: 若 dp[i-1] \leq 0dp[i−1]≤0 ,说明 dp[i - 1]dp[i−1] 对 dp[i]dp[i] 产生负贡献,即 dp[i-1] + nums[i]dp[i−1]+nums[i] 还不如 nums[i]nums[i] 本身大。 * 当 dp[i - 1] > 0dp[i−1]>0 时:执行 dp[i] = dp[i-1] + nums[i]dp[i]=dp[i−1]+nums[i] @@ -183,4 +183,102 @@ public int climbStairs(int n) { } return max; } +``` + + +## 4 传递信息 + +### 问题描述 +小朋友 A 在和 ta 的小伙伴们玩传信息游戏,游戏规则如下: + +有 n 名玩家,所有玩家编号分别为 0 ~ n-1,其中小朋友 A 的编号为 0 +每个玩家都有固定的若干个可传信息的其他玩家(也可能没有)。传信息的关系是单向的(比如 A 可以向 B 传信息,但 B 不能向 A 传信息)。 +每轮信息必须需要传递给另一个人,且信息可重复经过同一个人 +给定总玩家数 n,以及按 [玩家编号,对应可传递玩家编号] 关系组成的二维数组 relation。返回信息从小 A (编号 0 ) 经过 k 轮传递到编号为 n-1 的小伙伴处的方案数;若不能到达,返回 0。 + +示例 1: +``` +输入:n = 5, relation = [[0,2],[2,1],[3,4],[2,3],[1,4],[2,0],[0,4]], k = 3 + +输出:3 + +解释:信息从小 A 编号 0 处开始,经 3 轮传递,到达编号 4。共有 3 种方案,分别是 0->2->0->4, 0->2->1->4, 0->2->3->4。 +``` + +### 问题分析 + + +### 策略选择 +* 有三种不同的策略选择:广度优先搜索、深度优先搜索、动态规划。本文采用动态规划的思路,实际上与广度优先搜索的思路是一致的。看在第k步能到达的所有节点。 + +### 算法设计 + + +* **状态定义**dp[j] 为经过 i轮传递到编号j 的玩家的方案数,其中k0≤i≤k,n0≤j>& relation, int k) { + // // 构建邻接矩阵 + // vector> vec(n,vector(n,0)); + // for(auto a:relation){ + // vec[a[0]][a[1]]=1; + + // } + // // for(int i=0;i result; + // result.push_back(0); + // for(int i=0;i temp; + // for(auto a:result){ + // for(int j=0;j dp(n,0); + dp[0]=1; + for(int i=0;i temp(n,0); + for(auto a: relation){ + temp[a[1]]+=dp[a[0]]; + } + dp.assign(temp.begin(),temp.end()); + } + return dp[n-1]; + + } +}; ``` \ No newline at end of file diff --git a/算法/A类:基本算法/image/2021-07-23-22-46-02.png b/算法/A类:基本算法/image/2021-07-23-22-46-02.png new file mode 100644 index 00000000..1091299c Binary files /dev/null and b/算法/A类:基本算法/image/2021-07-23-22-46-02.png differ diff --git a/算法/A类:基本算法/image/2021-07-23-22-46-11.png b/算法/A类:基本算法/image/2021-07-23-22-46-11.png new file mode 100644 index 00000000..1091299c Binary files /dev/null and b/算法/A类:基本算法/image/2021-07-23-22-46-11.png differ diff --git a/算法/B类:数据结构算法/4.4 线性区间操作.md b/算法/B类:数据结构算法/4.4 线性区间操作.md index 17ceb6ca..9e5dd29e 100644 --- a/算法/B类:数据结构算法/4.4 线性区间操作.md +++ b/算法/B类:数据结构算法/4.4 线性区间操作.md @@ -94,4 +94,81 @@ public: return ans; } }; +``` + + + +## 2 区间覆盖问题 + +### 问题描述 + +给你一个二维整数数组 ranges 和两个整数 left 和 right 。每个 ranges[i] = [starti, endi] 表示一个从 starti 到 endi 的 闭区间 。 + +如果闭区间 [left, right] 内每个整数都被 ranges 中 至少一个 区间覆盖,那么请你返回 true ,否则返回 false 。 + +已知区间 ranges[i] = [starti, endi] ,如果整数 x 满足 starti <= x <= endi ,那么我们称整数x 被覆盖了。 + +  + +示例 1: +``` +输入:ranges = [[1,2],[3,4],[5,6]], left = 2, right = 5 +输出:true +解释:2 到 5 的每个整数都被覆盖了: +- 2 被第一个区间覆盖。 +- 3 和 4 被第二个区间覆盖。 +- 5 被第三个区间覆盖。 +``` +### 问题分析 + +* 区间覆盖问题 + +### 策略选择 + +* 数据结构:数组 +* 算法选择:线性区间操作 +### 算法设计 +* 遍历 \textit{ranges}ranges 中的所有区间 [l, r][l,r],将区间内每个整数的 \textit{cnt}cnt 值加上 11。遍历结束后,检查 [\textit{left},\textit{right}][left,right] 内的每个整数的 \textit{cnt}cnt 值是否均大于 00,是则返回 \texttt{true}true,否则返回 \texttt{false}false。 +* 在维护完差分数组 \textit{diff}diff 后,我们遍历 \textit{diff}diff 求前缀和得出覆盖每个整数的区间数量。下标 ii 对应的被覆盖区间数量即为初始数量 00 加上 [1, i][1,i] 闭区间的变化量之和。在计算被覆盖区间数量的同时,我们可以一并判断 [\textit{left}, \textit{right}][left,right] 闭区间内的所有整数是否都被覆盖。 + +### 算法分析 +* 时间复杂度:O(n + l) +* 空间复杂度:O(l) +### 算法实现 + +```C++ +class Solution { +public: + bool isCovered(vector>& ranges, int left, int right) { + // 一种差分数组的方法。 + vector vec(right-left+2,0); + for(auto k:ranges){ + if(k[0]>right || k[1]right){ + vec[right-left+1]--; + } + else{ + vec[k[1]-left+1]--; + } + } + + int m = 0; + for(int a =left;a<=right;a++){ + m+=vec[a-left]; + if(m<=0){ + return false; + } + } + return true; + + } +}; ``` \ No newline at end of file diff --git a/算法/B类:数据结构算法/4.5 链表与映射.md b/算法/B类:数据结构算法/4.5 链表与映射.md new file mode 100644 index 00000000..a0561dd8 --- /dev/null +++ b/算法/B类:数据结构算法/4.5 链表与映射.md @@ -0,0 +1,94 @@ +# 链表与映射 + + +## 复制带随机指针的链表 + +### 问题描述 + +给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。 + +构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。 + +例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。 + +返回复制链表的头节点。 + +用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示: + +val:一个表示 Node.val 的整数。 +random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为  null 。 +你的代码 只 接受原链表的头节点 head 作为传入参数。 + +  + +示例 1: + +![](image/2021-07-23-13-09-12.png) +``` +输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]] +输出:[[7,null],[13,0],[11,4],[10,2],[1,0]] +``` + +### 问题分析 + +* 需要建立原链表节点到新链表节点的映射。这个映射本可以通过添加子段实现,但是不能添加。只能使用一个map完成链表映射了。 + +### 策略选择 + + + +### 算法设计 + +### 算法分析 + +### 算法实现 + +```C++ +/* +// Definition for a Node. +class Node { +public: + int val; + Node* next; + Node* random; + + Node(int _val) { + val = _val; + next = NULL; + random = NULL; + } +}; +*/ +class Solution { +public: + Node* copyRandomList(Node* head) { + if(head==nullptr)return nullptr; + // 使用vector,修改原链表的方法不行。 + // 使用map建立原链表到新链表的映射 + map m; + Node* old_head = head; + Node* temp_old = head; + Node* new_head = new Node(head->val); + Node* temp_new = new_head; + while(temp_old->next!=nullptr){ + m[temp_old]=temp_new; + temp_new->next = new Node(temp_old->next->val); + + temp_old=temp_old->next; + temp_new=temp_new->next; + + } + m[temp_old]=temp_new; + + temp_old = head; + while(temp_old!=nullptr){ + if(temp_old->random!=nullptr){ + m[temp_old]->random=m[temp_old->random]; + } + temp_old=temp_old->next; + } + + return new_head; + } +}; +``` \ No newline at end of file diff --git a/算法/B类:数据结构算法/image/2021-07-23-13-09-12.png b/算法/B类:数据结构算法/image/2021-07-23-13-09-12.png new file mode 100644 index 00000000..73e032fb Binary files /dev/null and b/算法/B类:数据结构算法/image/2021-07-23-13-09-12.png differ diff --git a/读书思考/简介.md b/读书思考/简介.md new file mode 100644 index 00000000..b751406b --- /dev/null +++ b/读书思考/简介.md @@ -0,0 +1,3 @@ +学而不思则罔,思而不学则殆。 + +深刻体会。每天思考一堆东西,沉浸在自己发现的小规律和小感悟当中,实际上,书中早有成套的理论,概括升华了你的结论。仅仅通过个人的无休止的思考得到的知识和觉悟始终是优先的,思而不学则殆,非常关键。以后多读书,在这里整理一下自己的读书笔记吧。 \ No newline at end of file