算法岗
地平线面试记录
- 手推反向传播(求导)
- 编程题两道
- 画菱形(递归)
- 最长对称字串
- opencv用过吗?resize的插值方式。
- Linux下遍历文件夹下的png文件
- python怎么遍历文件夹下的所有png文件
- SSD怎么回归位置的?
- SSD和YOLO的区别
- SSD相对YOLO其中容易被忽视的一点: 去掉了YOLO的fc,纯CNN,所以可对任意大小的图片进行识别。
- ssd 有multi-scale:卷积操作在不同scale的feature maps上;yolo只有single scale。
- ssd使用default boxes 加上 various scales/aspect ratios:对不同scale的feature maps,采用不同尺寸和比例的default boxes 变形;这和yolo的anchor boxes是不同的,印象里yolo的anchor boxes不变形。
- ssd 没有fc layer,yolo有。
- loss不一样,我印象里,yolo还有个object和not object一项,因为yolo需要把一张图片分割成grid cells,只有一个cell包含了某个object的center。但是ssd并不需要分割成grid,没有cell和object的conrrespondence。
- 精确检索比赛的具体流程
虹软面试记录
- Adaboost的是怎么确定弱分类器的?(交叉熵)
- 交叉熵
- SSD和YOLO的区别?
- 类似推导反向求导
- 矩阵的基础知识。比如秩与解的关系。
腾讯算法笔试题型
单因素方差分析,假设检验
方差分析:方差分析就是对试验数据进行分析,检验方差相等的多个正态总体均值是否相等,进而判断各因素对试验指标的影响是否显著
网易深度学习笔试
SVM,Faster RCNN,LOSS
开发岗
拼多多
- 进程、线程和协程的区别
- 概念
- 进程:进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。每个进程都有自己的独立内存空间,不同进程通过进程间通信来通信。由于进程比较重量,占据独立的内存,所以上下文进程间的切换开销(栈、寄存器、虚拟内存、文件句柄等)比较大,但相对比较稳定安全。
- 线程:线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。线程间通信主要通过共享内存,上下文切换很快,资源开销较少,但相比进程不够稳定容易丢失数据。
- 协程:协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。
- 区别:
- 概念
进程多与线程比较:
线程是指进程内的一个执行单元,也是进程内的可调度实体。线程与进程的区别:
- 地址空间:线程是进程内的一个执行单元,进程内至少有一个线程,它们共享进程的地址空间,而进程有自己独立的地址空间
- 资源拥有:进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源
- 线程是处理器调度的基本单位,但进程不是
- 二者均可并发执行
- 每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口,但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制
协程多与线程进行比较”
- 一个线程可以多个协程,一个进程也可以单独拥有多个协程,这样python中则能使用多核CPU。
- 线程进程都是同步机制,而协程则是异步
- 协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态
- TCP的滑动窗口
- 为什么要三次握手
- 为什么要用虚函数
- 介绍一下STL
- 说说c++11的新特性
- 编程:硬币组合问题
- 编程:给出给个节点的id和其父节点的id,构建一个多叉树
- 本来想问数据库的没问
360面试
- 线程的通信方式
- 构造顺序
- 析构顺序
- sizeof(class A)
- n+1个整数,都在1~n之间,只有一个重复,怎么做?
- 假设第一个是k,可以和第k个换,这样循环,不用额外空间
- 黑名单实现(域名匹配)
C++基础知识
C++内存空间
一个C++程序编译以后占用的内存分为如下几个部分:
栈:由编译器自动分配释放,存放函数的参数值,局部变量的值。在一个进程中,位于用户虚拟地址空间顶部的是用户栈,编译器用它来实现函数的调用。
堆:由程序员分配和释放,若程序员不释放,则程序结束时被操作系统回收。存放由new、malloc分配的内存,可动态扩展和收缩。
全局区(静态区):全局变量和静态变量是存放在一起的,初始化的全局变量和初始化的静态变量在一块区域;未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。
文字常量区:常量字符串放在这里,程序结束后由操作系统释放。
程序代码区:存放函数体的二进制代码。
堆和栈的主要区别
- 管理的方式不同。栈由编译器自动管理,无需手动控制;堆由程序员控制,容易产生内存泄漏。
- 能否产生碎片。对于堆来说,频繁地new/delete势必造成内存空间的不连续,从而造成大量碎片,使程序效率降低;对于栈来说,不会存在这个问题,因为栈是后进先出的队列,一一对应,不会出现某个内存块从栈中间弹出。
- 生长方向。对于堆来说,生长方向向上,向着内存地址增加的地方;对于栈,生长方向向下,向着内存地址减小的方向。
- 分配效率:栈是计算机系统提高的数据结构,操作系统在底层对栈提供支持,分配专门的寄存器存放栈的地址,压栈出栈有专门的指令执行,这就决定了栈的效率比较高。对于堆则是由C/C++函数库提供,显然栈的效率比堆高。
1234567891011121314151617 |
int a = 0; //全局初始化区char *p1; //全局未初始化区 int (){ int b; //栈区 char s[] = "abc"; //栈区 char *p2; //栈区 char *p3 = "123456"; //123456在常量区,指针p3在栈上。 static int c =0; //全局(静态)初始化区 p1 = (char *)malloc(10); p2 = (char *)malloc(20); //分配得来得10和20字节的区域就在堆区。 strcpy(p1, "123456"); //123456放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。} |
C++复习记录
- 静态局部变量的作用:保存函数每次执行后的结果,以便下次调用函数时,继续使用上次计算的结果。
- 宏定义可出现在程序中的任何一行。
- 宏的作用域:从定义开始到文件结束,或者使用
#undef
指令终止宏。如果在此区间有包含文件#include
指令,那么宏作用域会延伸到被包含的整个文件。 - 宏定义无须分号结尾,但是如果有不报错。
- 如果字符串中出现宏名,则不进行宏展开。
- 有参宏:
#define <宏名>(<形参表>) <含形参的字符串>
- 条件编译:
- 宏名作为条件:
12345
#ifdef <宏名> <程序段>#else <程序段>#endif
- 常量表达式作为条件
1234567
#if <常量表达式> <程序段>#elif <常量表达式> <程序段>#else <程序段>#endif
- 宏名作为条件:
- 结构体中的静态变量的值为该结构类型的所有变量共享,访问的时候使用
::
。 - 所有枚举类型的大小都是4字节,即一个int值的大小。
typedef char str[10];
以这种方式给char[10]
起别名。const
:const *
:指针指向的内容不能变。* const
:指针不能变const * const
:都不能变,而且需要初始化
new
和delete
成对使用,delete []<指针变量>
:吧所执行的数组元素的内存空间归还。- 类的保护成员被自己类的成员函数访问,也能被自己的派生类访问。
- 一个类的对象不能作为自身类的成员,但是自身类的指针可以作为该类的成员。
- 类不允许对数据成员进行初始化,必须使用构造函数。
- 类和结构体的区别:
- c++中结构体也可以使用
private
等关键字 - 类成员的默认访问权限为
private
,而结构体成员的默认访问权限为public
- 结构体可以使用花括号进行初始化,但是类只能使用构造函数。
- 结构体也可以构造函数
- c++中结构体也可以使用
- 如果一个构造函数没有任何形参,或者所有形参都有默认值,这就是一个默认构造函数。
- 拷贝构造函数:
<类名>::<类名>(const <类名> &<对象名>)
- 如果一个类中显式的定义了一个拷贝构造函数,而没有其他构造函数,则该类不能创建对象。
- 用sizeof(类名)得到的大小不包括静态成员。静态成员函数主要用于管理类中的静态数据成员,不能直接访问非静态成员,不能定义为虚函数。
- 静态成员函数可以被继承,但不能定义为虚函数。
- 数据成员的指针:
<type><class name>::*<point name> = &<class name>::<class member name>
- 多态:
- 编译时刻的静态多态性:函数重载和运算符重载
- 运行时刻的动态多态性:继承和虚函数
- 虚基类是为了防止二义性,继承方式为在:之后加上virtual,只能产生一个子对象。
- 若不使用虚函数,则调用函数时,是由指针类型决定的;反之是由对象的实际类型决定的。
- 如果一个类含有纯虚函数,那么此类就称为抽象类(接口)。
virtual <返回类型> name (<形参表>) = 0
- 运算符重载:形参数比运算符目数少一个
- 友元函数:将类外函数用
friend
修饰,可以访问类内所有成员。 - 虚函数不能是静态成员函数,也不能是友元函数。
- 二级指针可以用来访问二维数组,但不能直接指向一个二维数组。
- 模板与有参宏的区别:
1
- 宏展开时编译器不能检查类型兼容性
- 若
cout<<max(x,++y)
,则y会计算两次 - 宏扩展属于预处理,编译是针对宏扩展之后的代码进行,编译错误只能给出宏扩展之后的代码错误,而不是宏定义自身的错误。
- 重载类型转换函数:
operator type()
- RTTI:运行时类型信息,
typeid(<表达式>).name()
- explicit 可以有效得防止构造函数的隐式转换带来的错误或者误解
https://www.cnblogs.com/cutepig/archive/2009/01/14/1375917.html
C++ string的用法和例子
使用场合:
string 是 C++ 标准库的一个重要的部分,主要用于字符串处理。可以使用输入输出流方式直接进行操作,也可以通过文件等手段进行操作。同时 C++ 的算法库对 string 也有着很好的支持,而且 string 还和 c 语言的字符串之间有着良好的接口。虽然也有一些弊端,但是瑕不掩瑜。
其中使用的代码多数都是来自 cpp 官网,因为例子非常全。
声明和初始化方法:
想使用 string 首先要在头文件当中加入
声明方式也很简单
声明:
12 |
string s;//声明一个string 对象string ss[10];//声明一个string对象的数组 |
初始化:
使用等号的初始化叫做拷贝初始化,不使用等号的初始化叫做直接初始化。
123456789101112131415161718192021222324252627 |
#include <bits/stdc++.h>using namespace std; int (){ ios::sync_with_stdio(false); string s;//默认初始化,一个空字符串 string s1("ssss");//s1是字面值“ssss”的副本 string s2(s1);//s2是s1的副本 string s3=s2;//s3是s2的副本 string s4(10,'c');//把s4初始化 string s5="hiya";//拷贝初始化 string s6=string(10,'c');//拷贝初始化,生成一个初始化好的对象,拷贝给s6 //string s(cp,n) char cs[]="12345"; string s7(cs,3);//复制字符串cs的前3个字符到s当中 //string s(s2,pos2) string s8="asac"; string s9(s8,2);//从s2的第二个字符开始拷贝,不能超过s2的size //string s(s2,pos2,len2) string s10="qweqweqweq"; string s11(s10,3,4);//s4是s3从下标3开始4个字符的拷贝,超过s3.size出现未定义 return 0;} |
字符串处理:
substr 操作:
注意 substr 没有迭代器作为参数的操作
123456789101112131415 |
#include <bits/stdc++.h>using namespace std;int main(){ ios::sync_with_stdio(false); string s="abcdefg"; //s.substr(pos1,n)返回字符串位置为pos1后面的n个字符组成的串 string s2=s.substr(1,5);//bcdef //s.substr(pos)//得到一个pos到结尾的串 string s3=s.substr(4);//efg return 0;} |
如果输入的位置超过字符的长度,会抛出一个 out_of_range 的异常
insert 操作:
代码来自 cpp 官网,经过自己的整理
注意用迭代器当参数和无符号数当参数的区别
123456789101112131415161718192021222324252627282930313233343536 |
#include <bits/stdc++.h>using namespace std;int main(){ ios::sync_with_stdio(false); string str="to be question"; string str2="the "; string str3="or not to be"; string::iterator it; //s.insert(pos,str)//在s的pos位置插入str str.insert(6,str2); // to be the question //s.insert(pos,str,a,n)在s的pos位置插入str中插入位置a到后面的n个字符 str.insert(6,str3,3,4); // to be not the question //s.insert(pos,cstr,n)//在pos位置插入cstr字符串从开始到后面的n个字符 str.insert(10,"that is cool",8); // to be not that is the question //s.insert(pos,cstr)在s的pos位置插入cstr str.insert(10,"to be "); // to be not to be that is the question //s.insert(pos,n,ch)在s.pos位置上面插入n个ch str.insert(15,1,':'); // to be not to be: that is the question //s.insert(s.it,ch)在s的it指向位置前面插入一个字符ch,返回新插入的位置的迭代器 it = str.insert(str.begin()+5,','); // to be, not to be: that is the question //s.insert(s.it,n,ch)//在s的it所指向位置的前面插入n个ch str.insert (str.end(),3,'.'); // to be, not to be: that is the question... //s.insert(it,str.ita,str.itb)在it所指向的位置的前面插入[ita,itb)的字符串 str.insert (it+2,str3.begin(),str3.begin()+3); // to be, or not to be: that is the question... return 0;} |
erase 操作:
用来执行删除操作
删除操作有三种
- 指定 pos 和 len,其中 pos 为为起始位置,pos 以及后面 len-1 个字符串都删除
- 迭代器,删除迭代器指向的字符
- 迭代器范围,删除这一范围的字符串,范围左闭右开
代码来自 cpp 官网
1234567891011121314151617181920212223 |
#include <iostream>#include <string> int main (){ std::string str ("This is an example sentence."); std::cout << str << 'n'; // "This is an example sentence." str.erase (10,8); // ^^^^^^^^ //直接指定删除的字符串位置第十个后面的8个字符 std::cout << str << 'n'; // "This is an sentence." str.erase (str.begin()+9);// ^ //删除迭代器指向的字符 std::cout << str << 'n'; // "This is a sentence." // ^^^^^ str.erase (str.begin()+5, str.end()-9); //删除迭代器范围的字符 std::cout << str << 'n'; // "This sentence." return 0;} |
append 和 replace 操作:
append 函数可以用来在字符串的末尾追加字符和字符串。由于 string 重载了运算符,也可以用 += 操作实现
repalce 顾名思义,就是替换的意思,先删除,后增加。
代码来自 cpp 官网,附上自己的解释
12345678910111213141516171819202122232425262728 |
#include <iostream>#include <string> int main (){ std::string str; std::string str2="Writing "; std::string str3="print 10 and then 5 more"; //直接追加一个str2的字符串 str.append(str2); // "Writing " //后面追加str3第6个字符开始的3个字符串 str.append(str3,6,3); // "10 " //追加字符串形参的前5个字符 str.append("dots are cool",5); // "dots " //直接添加 str.append("here: "); // "here: " //添加10个'.' str.append(10u,'.'); // ".........." //添加str3迭代器范围的字符串 str.append(str3.begin()+8,str3.end()); // " and then 5 more" //最后这个比较特殊,意思是添加5个'A',实际上参数里面的65对应的asc码就是65 str.append<int>(5,65); // "....." //字符串追加也可以用重载运算符实现 str+="lalala"; std::cout << str << 'n'; return 0;} |
replace 的使用方法,replace 支持使用无符号整数寻找位置,也支持用迭代器寻找位置
123456789101112131415161718192021大专栏 一切为了offerline">22232425262728293031323334 |
#include <iostream>#include <string> int main (){ std::string base="this is a test string."; std::string str2="n example"; std::string str3="sample phrase"; std::string str4="useful."; // replace signatures used in the same order as described above: // Using positions: 0123456789*123456789*12345 std::string str=base; // "this is a test string." //第9个字符以及后面的4个字符被str2代替 str.replace(9,5,str2); // "this is an example string." (1) //第19个字符串以及后面的5个字符用str的第7个字符以及后面的5个字符代替 str.replace(19,6,str3,7,6); // "this is an example phrase." (2) //第8个字符以及后面的9个字符用字符串参数代替 str.replace(8,10,"just a"); // "this is just a phrase." (3) //第8个字符以及后面的5个字符用字符串参数的前7个字符替换 str.replace(8,6,"a shorty",7); // "this is a short phrase." (4) //第22以及后面的0个字符用3个叹号替换 str.replace(22,1,3,'!'); // "this is a short phrase!!!" (5) //迭代器的原理同上 // Using iterators: 0123456789*123456789* str.replace(str.begin(),str.end()-3,str3); // "sample phrase!!!" (1) str.replace(str.begin(),str.begin()+6,"replace"); // "replace phrase!!!" (3) str.replace(str.begin()+8,str.begin()+14,"is coolness",7); // "replace is cool!!!" (4) str.replace(str.begin()+12,str.end()-4,4,'o'); // "replace is cooool!!!" (5) str.replace(str.begin()+11,str.end(),str4.begin(),str4.end());// "replace is useful." (6) std::cout << str << 'n'; return 0;} |
以上的 replace 操作可以用 insert 和 erase 的操作组合替换,但是 replace 操作更加方便。
assign 操作:
assign 操作在一起列容器当中都存在,比如 vector 等等。是一个很基本的操作函数,string 使用 assign 可以灵活的对其进行赋值。
代码来自 cpp 官网
123456789101112131415161718192021222324252627282930313233 |
#include <iostream>#include <string> int main (){ std::string str; std::string base="The quick brown fox jumps over a lazy dog."; // used in the same order as described above: //直接把base赋值给str str.assign(base); std::cout << str << 'n'; //把base第10个字符以及后面的8个字符赋给str str.assign(base,10,9); std::cout << str << 'n'; // "brown fox" //把参数中的0到6个字符串赋给str str.assign("pangrams are cool",7); std::cout << str << 'n'; // "pangram" //直接使用参数赋值 str.assign("c-string"); std::cout << str << 'n'; // "c-string" //给str赋值10个'*'字符 str.assign(10,'*'); std::cout << str << 'n'; // "**********" //赋值是10个'-' str.assign<int>(10,0x2D); std::cout << str << 'n'; // "----------" //指定base迭代器范围的字符串 str.assign(base.begin()+16,base.end()-12); std::cout << str << 'n'; // "fox jumps over" return 0;} |
string 的搜索操作:
string 类中提供了很多性能优秀,使用方便的成员方法。而且在泛型算法当中也有很多实用的技巧。
find 和 rfind 函数:
find 函数主要是查找一个字符串是否在调用的字符串中出现过,大小写敏感。
代码来自 cpp 官网
1234567891011121314151617181920212223242526272829303132 |
#include <bits/stdc++.h>using namespace std; int main(){ ios::sync_with_stdio(false); std::string str ("There are two needles in this haystack with needles."); std::string str2 ("needle"); // different member versions of find in the same order as above: //在str当中查找第一个出现的needle,找到则返回出现的位置,否则返回结尾 std::size_t found = str.find(str2); if (found!=std::string::npos) std::cout << "first 'needle' found at: " << found << 'n'; //在str当中,从第found+1的位置开始查找参数字符串的前6个字符 found=str.find("needles are small",found+1,6); if (found!=std::string::npos) std::cout << "second 'needle' found at: " << found << 'n'; //在str当中查找参数中的字符串 found=str.find("haystack"); if (found!=std::string::npos) std::cout << "'haystack' also found at: " << found << 'n'; //查找一个字符 found=str.find('.'); if (found!=std::string::npos) std::cout << "Period found at: " << found << 'n'; //组合使用,把str2用参数表中的字符串代替 // let's replace the first needle: str.replace(str.find(str2),str2.length(),"preposition"); std::cout << str << 'n'; return 0;} |
rfind 函数就是找最后一个出现的匹配字符串,返回的位置仍然是从前往后数的。
12345678910111213141516171819 |
#include <bits/stdc++.h>using namespace std; int main(){ ios::sync_with_stdio(false); std::string str ("The sixth sick sheik's sixth sheep's sick."); std::string key ("sixth");// ^ //rfind是找最后一个出现的匹配字符串 std::size_t found = str.rfind(key); if (found!=std::string::npos) { cout<<found<<endl;//输出23 str.replace (found,key.length(),"seventh");//找到的sixth替换成seventh } std::cout << str << 'n'; return 0;} |
查找的效率非常高,我没看过 stl 源码剖析,但是感觉是用 kmp 实现的。呵呵,可以自己写一个。
find_….of 函数:
- find_first_of(args) 查找 args 中任何一个字符第一次出现的位置
- find_last_of(args) 最后一个出现的位置
- find_fist_not_of(args) 查找第一个不在 args 中的字符
- find_last_not_of 查找最后一个不在 args 中出现的字符
1234567891011121314151617181920212223242526 |
#include <bits/stdc++.h>using namespace std; int main(){ ios::sync_with_stdio(false); std::string str1 ("Please, replace the vowels in this sentence by asterisks."); std::size_t found1 = str1.find_first_of("aeiou"); //把所有元音找出来用*代替 while (found1!=std::string::npos) { str1[found1]='*'; found1=str1.find_first_of("aeiou",found1+1); } std::cout << str1 << 'n'; //在str2中找到第一个不是消协英文字母和空格的字符 std::string str2 ("look for non-alphabetic characters..."); std::size_t found2 = str2.find_first_not_of("abcdefghijklmnopqrstuvwxyz "); if (found2!=std::string::npos) { std::cout << "The first non-alphabetic character is " << str2[found2]; std::cout << " at position " << found2 << 'n'; } return 0;} |
find_last_of 和 find_last_not_of 与 first 基本相同,就不写例子代码了。
比较与转换:
类似 c 语言的字符串比较函数 strcmp 函数一样,支持字符串比较操作,同时也类似 python、C# 语言中的函数一样,支持把数字和字符串转换。有些特性是 C++11 当中才有。
注意编译器 bug:
在 MinGW 编译器当中如果版本低于 3.8,虽然支持 c++11 但是里面有一个 bug,就是不支持字符串和数组的转换!要更新 MinGW 的版本才可以,或者直接使用 g++。
compare 函数:
和 strcmp 函数一样,如果两个字符串相等,那么返回 0,调用对象大于参数返回 1,小于返回 - 1。
在 compare 当中还支持部分比较,里面有 6 个参数可以设置。
12345678910111213141516171819202122232425262728293031 |
#include <bits/stdc++.h>using namespace std; int main(){ ios::sync_with_stdio(false); string s1="123",s2="123"; cout<<s1.compare(s2)<<endl;//0 s1="123",s2="1234"; cout<<s1.compare(s2)<<endl;//-1 s1="1234",s2="123"; cout<<s1.compare(s2)<<endl;//1 std::string str1 ("green apple"); std::string str2 ("red apple"); if (str1.compare(str2) != 0) std::cout << str1 << " is not " << str2 << 'n'; //str1的第6个字符以及后面的4个字符和参数比较 if (str1.compare(6,5,"apple") == 0) std::cout << "still, " << str1 << " is an applen"; if (str2.compare(str2.size()-5,5,"apple") == 0) std::cout << "and " << str2 << " is also an applen"; //str1的第6个字符以及后面的4个字符和str2的第4个字符以及后面的4个字符比较 if (str1.compare(6,5,str2,4,5) == 0) std::cout << "therefore, both are applesn"; return 0;} |
由于 string 重载了运算符,可以直接用 >,<,== 来进行比较,也很方便。
数值转换:
在 io 的部分有过数值和字符串相互转换的例子,使用的是 stringstream 函数,在 c++11 当中有定义好的现成的函数取调用,非常方便。
string 和数值转换 | |
---|---|
to_string(val) | 把 val 转换成 string |
stoi(s,p,b) | 把字符串 s 从 p 开始转换成 b 进制的 int |
stol(s,p,b) | long |
stoul(s,p,b) | unsigned long |
stoll(s,p,b) | long long |
stoull(s,p,b) | unsigned long long |
stof(s,p) | float |
stod(s,p) | double |
stold(s,p) | long double |
// 注意,下段代码在 MinGw 中会报错!即使使用 c++11 编译也一样,无法识别 to_string!
1234567891011121314 |
#include <bits/stdc++.h>using namespace std; int main(){ ios::sync_with_stdio(false); string s1; s1=to_string(100); cout<<s1<<endl; int a=stoi(s1,0,10)+1; cout<<a<<endl; return 0;} |
数据结构
操作系统
- 解决hash冲突的几种方式
-
计算机网络
TCP/IP 网络编程 —— 理论基础
1、OSI 模型
2、TCP/IP 协议的四个层次
TCP/IP 协议的体系结构分为四层,这四层由高到低分别是:应用层、传输层、网络层(网际层)和链路层(网络接口层)。
(1)链路层
链路层在 TCP/IP 协议栈的最低层,也称为数据链路层或网络接口层,通常包括操作系统中的设备驱动程序和计算机中对应的网络接口卡。链路层的功能是把接收到的网络层数据报 (也称 IP 数据报) 通过该层的物理接口发送到传输介质上,或从物理网络上接收数据帧,抽出 IP 数据报并交给 IP 层。
(2)网络层 (Network Layer)
网络层也称为互联网层,由于该层的主要协议是 IP 协议,因而也可简称为 IP 层。它是 TCP/IP 协议栈中最重要的一层,主要功能是可以把源主机上的分组发送到互联网中的任何一台目标主机上。
(3)传输层 (Transport Layer)
我们通常所说的两台主机之间的通信其实是两台主机上对应应用程序之间的通信,传输层提供的就是应用程序之间的通信,也叫端到端 (End to End) 的通信。在 TCP/IP 协议族中传输层包含两个不同的传输协议:一个是 TCP(传输控制协议);另一个是 UDP(用户数据报协议)。
(4)应用层 (Application Layer)
应用层向使用网络的用户提供特定的、常用的应用程序,如使用最广泛的远程登录 (Telnet)、文件传输协议(FTP)、超文本传输协议(HTTP)、域名系统(DNS)、简单网络管理协议(SNMP) 和简单邮件传输协议 (SMTP) 等。要注意有些应用层协议是基于 TCP 协议的(如 FTP 和 HTTP 等),有些应用层协议是基于 UDP 协议的(如 SNMP 等)。
TCP/IP 协议分为四层结构,这四层结构中有两个重要的边界:一个是将操作系统与应用程序分开的边界,另一个是将高层互联网地址与低层物理网卡地址分开的边界。
- 操作系统边界
操作系统边界的上面是应用层,应用层处理的是用户应用程序 (用户进程) 的细节问题,提供面向用户的服务。
- 地址边界
地址边界的上层为网络层,网络层用于对不同的网络进行互联,连接在一起的所有网络为了能互相寻址,要使用统一的互联网地址 (IP 地址)。
3、通信模型
4、数据封装与解封过程
传输层协议TCP和UDP
这里只讨论使用TCP协议的网络编程,由于UDP的不可靠性,现在使用的越来越少,但是为了和TCP做对比,这里还是稍微提一下概念。
用户数据报协议(UDP)
UDP是一个简单的、无连接、不可靠的传输层协议,应用进程往一个UDP套接字写入一个消息,该消息随后被封装到一个UDP数据报,该UDP数据报进而被封装到一个IP数据报,然后发完目的地。UDP不保证UDP数据报会到达最终目的地,不保证各个数据报达到目的地的先后顺序,也不保证每个数据报只到达一次。
? 每个UDP数据报后有一个长度,在数据报正确到达目的地后,长度会随数据传递给应用程序,所以通常情况下在应用程序看来,UDP每次接收到的都是与发送的大小一致的数据包,而TCP是一个字节流协议,传输的数据是没有边界的。
? 下图显示的是UDP的首部,从中可以看出,UDP其实就是在IP的基础上多提供的了一个端口,可以实现通过端口来将数据传送给特定的进程。
传输控制协议(TCP)
TCP提供了面向连接的,靠性的服务,与UDP相比,它具有确认、超时重传、流量控制、拥塞控制等机制。
在两端进行通信前必须先建立连接,当TCP向另一端发送数据时,将启动一个定时器,它要求对端返回一个确认,如果在定时器超时后还没有收到确认,TCP就自动重传数据并等待更长时间。在数次重传失败后TCP才放弃。
? 当TCP接收到另一端TCP发来的数据后,将发送一个确认,这个确认不一定是立即发送的,通常将在推迟一段时候后发送(延时确认机制)。
? TCP将保持她首部和数据的校验和,这是一个端到端的校验和,目的是检验数据在传输过程中的任何变化,如果收到端的校验和有差错,TCP将丢弃这个报文段并发送确认,等待发送端超时重传。
? TCP并不保证数据一定会被对端接收,因为这是不可能做到的,如果有可能,TCP就将数据递送到对端,否则就通知用户。因此,TCP也不能被描述成是100%可靠的协议,它提供的是数据的可靠递送货故障的可靠通知。
? TCP含有用于动态估算客户和服务器之间的往返时间(round-trip time, RTT)的算法,以便它知道等待一个确认需要多长时间。
? TCP通过给其中的每个字节关联一个序列号对所发送的数据进行排序。若接收端接收到的数据非顺序到达,接收端TCP将先根据它们的序列化重新排序,再把结果数据传递给接收应用。若接收到了重复数据,它将根据序列号判定数据是重复的,从而丢弃重复数据。
? TCP总是告知对端在任何时刻它一次能够从对端接收多少字节的数据,这称为通知窗口,在任何时刻,该窗口指出接收缓冲区当前可用的空间量,从而确保发送端发送的数据不会使接收缓冲区溢出。
TCP服务端编程的一般步骤为:
- 调用socket函数,创建一个套接字描述符。
- 创建网络地址结构,指定要监听的IP和端口号。
- 调用bind函数,将套接字描述符与网络地址结构绑定。
- 调用listen函数,将套接字描述符转为监听套接字,表示该描述符是用于从指定地址和端口接收连接的。
- 调用accept函数来获取链接。
- 得到连接后使用read和write函数完描述符里读写数据。
- 完成后调用close关闭描述符。
TCP客户端端编程的一般步骤为:
- 调用socket函数,创建一个套接字描述符。
- 创建网络地址结构,指定要连接的服务端的IP和端口号。
- 调用connect函数连接服务端。
- 连接成功后调用read、write函数读写数据
- 完成后调用close关闭描述符。
其他问题汇总
红黑树
红黑树是一种近似平衡的二叉查找树,它能够确保任何一个节点的左右子树的高度差不会超过二者中较低那个的一陪。具体来说,红黑树是满足如下条件的二叉查找树(binary search tree):
- 每个节点要么是红色,要么是黑色。
- 根节点必须是黑色,每个叶子节点(NIL)是黑色
- 红色节点不能连续(也即是,红色节点的孩子和父亲都不能是红色)。
- 对于每个节点,从该点至null(树尾端)的任何路径,都含有相同个数的黑色节点。
在树的结构发生改变时(插入或者删除操作),往往会破坏上述条件3或条件4,需要通过调整使得查找树重新满足红黑树的条件。
算法类
生成式模型和判别式模型
卷积的作用
可以理解为一种混合信息的手段。是一个滤波器,每个卷积核都可以获得不同的信息。
激活函数的作用
用来加入非线性因素的,解决线性模型所不能解决的问题。
- tanh:双切正切函数,取值范围[-1,1]
- sigmoid:采用S形函数,取值范围[0,1]
- ReLU:简单而粗暴,大于0的留下,否则一律为0
池化的功能
逐步减少输入表征的空间尺寸。特别地,池化
- 使输入表征(特征维度)更小而易操作
- 减少网络中的参数与计算数量,从而遏制过拟合
- 增强网络对输入图像中的小变形、扭曲、平移的鲁棒性(输入里的微小扭曲不会改变池化输出——因为我们在局部邻域已经取了最大值/平均值)。
- 帮助我们获得不因尺寸而改变的等效图片表征。这非常有用,因为这样我们就可以探测到图片里的物体,不论那个物体在哪。
ROIPooling 和 ROIAlign
RoI Pooling
实现从原图ROI区域映射到卷积区域最后pooling到固定大小的功能,然后通过池化把该区域的尺寸归一化成卷积网络输入的尺寸。
ROIAlign
上面RoI Pooling从原图ROI映射到卷积区域,即原图ROI与特征图ROI之间的映射,使用了stride间隔的取整,使得特征图ROI再映射回原图ROI的时候有stride的误差。尤其经过最大值池化后的特征与原ROI之间的空间不对齐就更加明显了。
因此,ROIAlign从原图到特征图直接的ROI映射直接使用双线性插值,不取整,这样误差会小很多,经过池化后再对应回原图的准确性也更高些。
这里假设得到的浮点型坐标为(x,y),取其周围最近的四个点,在Y方向内插两次,再在X方向内插一次,得到新的值。ROI的形状是不变化的。
SVM的理解
为什么要用L2 loss?
光流场是什么
光流场是图片中每个像素都有一个x方向和y方向的位移,所以在上面那些光流计算结束后得到的光流flow是个和原来图像大小相等的双通道图像。
原文地址:https://www.cnblogs.com/liuzhongrong/p/12272373.html