昨天没完成,争取今天全部完成!!!加油~
算法练习
1. 设计LRU缓存结构
之前写过一次,忘记了,这次看着别人的答案理解了一遍,学会了使用迭代器,以及list的erase函数,map的find函数等用法。本来想使用acm模式的,但这个好像只能使用核心代码模式。
代码详情:
class Solution {
private:
int capacity_; //定义缓存容量
list<int> list_; //创建双向链表,存储值
unordered_map<int, pair<int,list<int>::iterator>> map_; //key对应key,value对应value和链表的迭代器
public:
Solution(int capacity){
// write code here
capacity_ = capacity;
}
int get(int key) {
// write code here
auto it = map_.find(key); //寻值,返回迭代器
if (it == map_.end()){ //不存在返回-1
return -1;
}
int value = it->second.first; //获取值
set(key,value); //更新值
return value;
}
void set(int key, int value){
// write code here
auto it = map_.find(key); //返回一个迭代器
if (it == map_.end() && map_.size() >= capacity_){ //迭代器等于末尾说明哈希表没有该值,并且缓存容量达到上限
map_.erase(list_.back()); //在哈希表中删除链表最后一个元素
list_.pop_back(); //弹出最后一个元素
}
if (it != map_.end()){ //说明哈希表里含有该值,需要移动该值到链首
list_.erase(it->second.second);
}
list_.push_front(key); //将key更新到链首
map_[key].first = value;
map_[key].second = list_.begin(); //更新哈希表中value的迭代器
}
};
/**
* Your Solution object will be instantiated and called as such:
* Solution* solution = new Solution(capacity);
* int output = solution->get(key);
* solution->set(key,value);
*/
2. 字符串出现次数的TopK问题
哈希表计算字符串出现次数,接着排序(先比数量,在比字符ASCII码大小)。
代码详情(ACM模式):
#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
#include <algorithm>
using namespace std;
class Solution {
public:
vector<vector<string>> topKstrings(vector<string>& strings, int k) {
vector<vector<string>> result; //存储答案
unordered_map<string, int> map_; //创建哈希表,key代表字符串,value代表该串数量
int n = strings.size();
for (int i = 0; i < n; ++i) {
if (map_.count(strings[i])) { //存在加一
map_[strings[i]] += 1;
}
else { //不存在初始化为0
map_[strings[i]] = 1;
}
}
vector<pair<int, string>> sort_list; //创建排序表,int存储该串数量,string存储字符串
for (auto m : map_) { //将哈希表数据导入排序表中
sort_list.push_back({ m.second,m.first });
}
sort(sort_list.begin(), sort_list.end(), [](pair<int, string> p1,pair<int, string> p2) { //根据数量和字符串排序
if (p1.first != p2.first) return p1.first > p2.first; //数量不同从大到小排序
else { //数量相同,按字符ASCII码大小,从小到大排
int i = 0;
while (p1.second[i] == p2.second[i]) {
if (i < p1.second.size() && i < p2.second.size()) {
++i;
}
else {
if (i == p1.second.size()) {
return false;
}
{
return true;
}
}
}
return p1.second[i] < p2.second[i];
}
});
for (int i = 0; i < k; ++i) {
result.push_back({ sort_list[i].second,to_string(sort_list[i].first) });
}
return result;
}
};
/*
a b c b
2
*/
int main() {
vector<string> strings; //存储字符串组
string tem; //存储字符串
while (cin >> tem) { //输入字符串
strings.push_back(tem);
if (getchar() == '\n') {
break;
}
}
int k = 0; //需要获取前k个数
cin >> k;
Solution sl;
vector<vector<string>> result = sl.topKstrings(strings, k);
//输出答案
int n = result.size();
for (int i = 0; i < n; ++i) {
cout << result[i][0] << ' ' << result[i][1] << endl;
}
return 0;
}
算法真题
1. 出模拟赛
这题没想出来,我使用的方法时间复杂度过高没通过,看了题解也没理解,下次再尝试。
面试题
1. 进程和线程以及它们的区别
进程是资源分配的基本单位,线程是程序执行的最小单位。
区别:
1. 进程拥有独立地址空间和资源,线程共享该进程的所有资源
2. 进程比线程更健壮,一个进程崩溃不会导致其他进程崩溃,一个线程崩溃会导致整个进程崩溃。
3. 进程开销比线程大。
2. TCP拥塞控制?
拥塞控制是防止过多的数据注入网络,导致网络中的路由器或链路过载。
拥塞控制流程:
1. 慢开始:最开始发送方的拥塞窗口为1,由小到大递增,每经过一个传输轮次,拥塞窗口cwnd加倍,当拥塞窗口cwnd超过慢开始门限,使用拥塞避免算法
2. 拥塞避免算法:每经过一个传输轮次,cwnd增加1,一旦发现网络拥塞,将慢开始门限设置为当前值的一半,并重新设置拥塞窗口cwnd为1,重新慢开始。
3. 快重传:接收方每收到一个失序的报文段就立即发出重复确认,发送方只要收到3个重复确认就立即重传。
4. 快恢复:当发送方连续收到三个重复确认,就将慢开始门限减半,将当前窗口设置为慢开始门限,并采用拥塞避免算法。
3. C/C++内存有哪几种类型?
C中内存分为:堆(malloc)、栈(局部变量、函数参数)、程序代码区(存放二进制代码)、全局/静态存储区(全局变量、static变量)和常量存储区(const)。C++有自由存储区。
4. 什么是死锁?死锁产生的条件?
死锁:在两个或者多个并发过程中,如果每个进程持有某种资源又等待其他进程释放资源,导致进程无法推进,称为死锁。通俗地讲,两个或多个进程无限期的阻塞、相互等待的一种状态。
死锁产生条件:
1. 互斥:资源属于非共享
2. 占有并等待。
3. 非抢占。
4. 循环等待。
5. TCP如何实现可靠连接?
TCP通过序列号、超时重传、检验和(检测包里面数据是否正确)、流量控制、滑动窗口、拥塞控制实现可靠性。
6. 堆和栈的区别?
1. 堆存放动态分配的对象。
2. 栈用来保存定义在函数内的非static对象。
3. 静态内存用来保存static对象。
4. 栈是编译器自动创建和销毁的。
7. 进程有哪几种状态?
1. 就绪状态:进程已获得除处理机以外的所需资源,等待分配处理机资源。
2. 运行状态: 占用处理机资源运行
3. 阻塞状态: 进程等待某种条件,处于无法执行状态。
8. TCP三次握手
第一次握手:客户端--》服务端(数据包:SYN=1,seq=J),客户端进入SYN_SENT状态。
第二次握手:服务端--》客户端(数据包:SYN=1,ACK=1,ack=J+1,seq=K),服务端进入SYN_RCVD状态。
第三次握手:客户端检查数据包是否准确,客户端--》服务端(数据包:ACK=1,ack=K+1),服务端检查数据包是否准确,两者进入ESTABLISHED状态。
9. 程序编译的过程?
四个过程:预处理(检查程序是否可以执行) --》编译(转换为汇编语言)--》汇编(转换为二进制机器指令)--》链接(链接其他文件)。
10. 分页和分段有什么区别(内存管理)?
段式存储:将程序的地址空间划分为若干段,每一段存储相同意义的信息。
页式存储:将程序的逻辑地址划分为固定大小的页,物理内存也划分同样大小的帧。
区别:
1. 目的不同:分页服务于系统管理,分段服务于用户,段内数据是一组有意义且相对完整的信息。
2. 大小不同:页的大小固定,段长度由功能决定。
3. 地址空间不同:段向用户提供二维地址空间,页向用户提供一维地址空间。
4. 信息共享:段是信息的逻辑单位,便于存储保护和信息共享,页的保护和共享受到限制。
5. 内存碎片:页式存储没有外碎片,但会有内碎片;段无内碎片,但会产生外碎片。
11. TCP四次挥手
第一次挥手:客户端--》服务端(FIN),客户端进入FIN_WAIT_1状态。客户端不再发送数据,但可以接收数据。
第二次挥手:服务端--》客户端(ACK),服务端进入CLOSE_WAIT状态。服务端开始处理剩下的数据。客户端接收ACK,进入FIN_WAIT_2状态。
第三次挥手:服务端--》客户端(FIN),服务端进入LAST_ACK状态。服务端不再发送数据。
第四次挥手:客户端--》服务端(ACK),客户端进入TIME_WAIT状态(防止最后的确认数据包丢失),服务端接收ACK,进入CLOSED状态,一段时间后,客户端也进入CLOSED状态。