扩展3
1、get和post区别
- 通常get的数据写在url里,post写在body里
- 服务器或浏览器可能会对url长度有限制,那么get的数据也会受限
- get会发一个tcp包,post可以发两个,第一次发header,如果是返回100则发送数据;否则则无权限。
2、HTTP部分报文头部
请求头:
accept:诸如text/html application/xml,表示客户端可以接收什么类型
host:服务器域名。一个IP可以有多个域名,使用host字段可以区分一个IP下的不同站点
user-agent:浏览器信息等
accept-encoding:浏览器支持的数据编码方式,gzip
connection:keep-alive
cookie:携带cookie信息
响应头:
content-encoding:文档的编码方法
content-type:text/html,文档的类型
set-cookie:设置cookie
server:Apache,服务器信息
connection:keep-alive
3、链接具体过程
链接是把一些可重定位目标文件(*.o)链接到一起生成可执行文件。
4、红眼睛蓝眼睛问题
岛上有5个红眼睛,95个蓝眼睛。岛民知道红色和蓝色的区别,不能看自己眼睛颜色,不能告诉别人他们眼睛的颜色,如果他知道自己是红眼睛就会挂。一天,一个游客告诉他们所有人“岛上有红眼睛”,那么会发生什么?
5个红眼睛会在第5天一起挂。
假如只有1个红眼睛,那么他马上就知道自己是红眼睛,第1天就会挂。(1)
假如有2个,第1天没事,第2天他们会发现对方没挂,但是他们都只看见1个红眼睛,由(1)可得如果只有1个红眼睛那么第1天就会挂,说明自己也是,那么他们第2天一起挂。
归纳可得,有n个红眼睛,第n天会一起挂。
5、循环右移数组K位
整体反转,翻转前k个,翻转后面。
6、交换两个数
a = a ^ b;
b = a ^ b;
a = a ^ b;
第二行等价b = a ^ b ^ b
,那么b = a
;第三行等价a = a ^ b ^ a
,即a = b
。
还有一种可能会越界的,但是和上面基本同理:
//可能越界
a = a + b;
b = a - b;
a = a - b;
7、为啥重载不能根据返回类型
因为调用时不能知道需要哪个返回类型。
比如:int add(int a, int b)
和double max(int a, int b)
,如果调用时有接收返回值还可以判断,但是如果忽略返回值,那么就不能判断要选择哪个了。
8、股票买卖系列
1.leetcode123:
限制只能买/卖各两次,每次买入前手里不能有股票,问最大收益。
逆序O(n)算出每个从i开始到n的最大差值dis[i]
,然后解为max{price[i] - min_pre + dis[i]}
。
2.leetcode309:
买之前手里必须没有持股,卖了之后第二天不能买卖,问最大收益。
设dp[i][0]
为持股最大收益,dp[i][1]
为不持股第二天冻结(当天卖了)最大收益,dp[i][2]
为不持股第二天不冻结最大收益。可得状态转移方程如下:
class Solution {
public:
// 0:持股, 1:不持股第二天冻结, 2:不持股第二天未冻结
int maxProfit(vector<int>& prices) {
int n = prices.size();
if (n <= 1)
return 0;
vector<vector<int> > dp(n, vector<int>(3));
dp[0][0] = -prices[0];
dp[0][1] = 0;
dp[0][2] = 0;
for (int i = 1; i < n; i++) {
dp[i][0] = max(dp[i - 1][0], dp[i - 1][2] - prices[i]);
dp[i][1] = dp[i - 1][0] + prices[i];
dp[i][2] = max(dp[i - 1][2], dp[i - 1][1]);
}
return max(dp[n - 1][2], dp[n - 1][1]);
}
};
3.leetcode188:
限制只能买/卖各k次,每次买入前手里不能有股票,问最大收益。
类似上面做法,dp[i][j][p]
表示第i天已经卖了j次是否持股。
class Solution {
public:
//第i天已经卖k是否持股
int maxProfit(int k, vector<int>& prices) {
int n = prices.size();
if(n <= 1) return 0;
else if(n / 2 <= k){
int ret = 0;
for(int i = 1; i < n; i++)
ret += max(0, prices[i] - prices[i - 1]);
return ret;
}
vector<vector<vector<int> > > dp(n, vector<vector<int> >(k + 1, vector<int>(2, 0)));
for(int i = 0; i <= k; i++){
dp[0][i][0] = 0;
dp[0][i][1] = -prices[0];
}
for(int i = 1; i < n; i++){
for(int j = 0; j <= k; j++){
if(j - 1 >= 0) dp[i][j][0] = max(dp[i - 1][j][0], dp[i - 1][j - 1][1] + prices[i]);
else dp[i][j][0] = dp[i - 1][j][0];
dp[i][j][1] = max(dp[i - 1][j][1], dp[i - 1][j][0] - prices[i]);
}
}
int Max = 0;
for(int i = 0; i <= k; i++)
Max = max(Max, dp[n - 1][i][0]);
return Max;
}
};
9、this指针
调用类的非静态成员函数时,编译器会自动传入一个隐含的参数this,它指向这个对象的地址。
10、LCA倍增
用dp[i][k]
表示i的第\(2^k\)辈节点(比如dp[i][0]
为父节点,dp[i][1]
为爷爷节点),所以i的\(2^{k-1}\)辈节点的\(2^{k-1}\)辈节点是i的\(2^k\)辈节点,状态转移方程dp[i][k] = dp[dp[i][k-1]][k-1]
,初始化dp数组复杂度O(nlogn)。
然后先让u和v跳到同一深度,然后从\(2^{max}\)一直一起往上跳跳到\(2^0\),这时保证了dp[u][0] == dp[v][0]
。
int lca(int u, int v){
if(deep[u] < deep[v]){
swap(u, v);
}
int d = deep[u] - deep[v];
for(int i = 20; i >= 0; i--){
if(d & (1 << i))
u = dp[u][i];
}
if(u == v) return u;
for(int i = 20; i >= 0; i--){
if(dp[u][i] != dp[v][i]){
u = dp[u][i];
v = dp[v][i];
}
}
return dp[u][0];
}
11、shared_ptr的线程安全
shared_ptr的引用计数是原子的,所以是线程安全的,但是读写指针是不安全的,所以读写时建议加锁。
12、单例模式线程安全
懒汉式:使用时才创建,(如果同时创建会内存泄漏)需考虑线程安全。
饿汉式:直接创建实例,本来就线程安全,因为静态属性初始化在主函数执行之前。
懒汉式:
C++11及以后局部静态变量只会初始化一次,并且是线程安全的
/***
*局部静态变量只会初始化一次,并且是线程安全的
***/
class Single{
public:
static Single& get(){ //返回的是引用
static Single instance;
return instance;
}
private:
Single(){}
~Single(){}
Single(const Single& obj){}
Single& operator = (Single &obj){}
};
直接加锁。
class Single{
public:
static Single* get(){
lock
if(instance == nullptr){
instance = new Single;
}
return instance;
}
private:
static Single* instance;
Single(){}
~Single(){}
Single(const Single& obj){}
Single& operator = (Single &obj){}
};
双检查锁DCL可能会失效,因为编译器会重排顺序。m_instance = new Singleton()
有三步:开辟对象的内存,初始化构造对象,把内存地址分配给指针。如果乱序,那么当二三两步乱序,那么先分配指针但是还没构造,就切换了,那么m_instance != nullptr
但是对象并未构造。
if(m_instance==nullptr){
Lock lock; //伪代码
if (m_instance == nullptr) {
m_instance = new Singleton();//可能失效
}
}
饿汉式:
class Single{
public:
static Single* instance;
static Single* get(){
return instance;
}
static void del(){
delete instance;
}
private:
Single(){}
~Single(){}
Single(const Single& obj){}
Single& operator = (Single &obj){}
};
//静态属性初始化在main之前
Single* Single::instance = new Single;