昨天没有完成,今天争取完成!!!冲呀,大厂offer我来啦。
算法题(牛客网)
1.求二叉树的层序遍历
这个上个星期刷过,与其他遍历不同,层序遍历用的是队列保存节点。
代码详情:
/**
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
class Solution {
public:
/**
*
* @param root TreeNode类
* @return int整型vector<vector<>>
*/
vector<vector<int> > levelOrder(TreeNode* root) {
// write code here
if (!root) return {};//算法第一步判断边界条件
vector<vector<int>> res; //保存答案
queue<TreeNode*> que; //保存遍历节点
que.push(root);
while(!que.empty()){
int size = que.size(); //记录这一层有多少节点要遍历
vector<int> ans; //保存当前层的节点值
while(size--){
root = que.front();
que.pop();
ans.push_back(root->val);
if(root->left) que.push(root->left); //存在左孩子,保存进队列
if(root->right)que.push(root->right); //同理
}
if (ans.size() != 0){
res.push_back(ans);
}
}
return res;
}
};
2.寻找第K大
题目要求了要用快速排序,所以不能使用堆排序了。
代码详情:
class Solution {
public:
int findKth(vector<int> a, int n, int K) {
// write code here
int l = 0,r = n-1; //左右指针
K = n-K; //将k换算成第k小
while(l <= r){
int mid = quickSort(a, l, r); //计算中间指针
if (mid == K){ //如果相等,说明该位置就是答案
return a[mid];
}
else if(mid < K){ //中间指针在答案左边,去右边接着找
l = mid + 1;
}
else{ //同理
r = mid - 1;
}
}
return -1;
}
int quickSort(vector<int>& nums,int l,int r){ //快排,寻找一个参考,左边都是小的,右边都是大的
int i = l+1,j = r;
int num = nums[l];
while(i <= j){
while(i <= r && num >= nums[i]){ //寻找比num大的数
i++;
}
while(j > l && num < nums[j]){ //寻找比num小的数
j--;
}
if (i >= j){
break;
}
swap(nums[i],nums[j]); //交换i,j
}
swap(nums[l],nums[j]); //记得把l换到该换的位置
return j;
}
};
3.两数之和
由于要求时间复杂度O(nlogn),普通的暴力枚举是不可行的,这里使用哈希表,一边查找,一边保存已查找的值。
代码详情:
class Solution {
public:
/**
*
* @param numbers int整型vector
* @param target int整型
* @return int整型vector
*/
vector<int> twoSum(vector<int>& numbers, int target) {
// write code here
unordered_map<int, int> map; //key保存数组数值,value保存数组下标
for(int i = 0;i < numbers.size();i++){
if (map.count(target - numbers[i])){ //查找哈希表是否存在一个值和当前值相加为target
return {map[target - numbers[i]] + 1,i + 1};
}
else{
map[numbers[i]] = i; //不存在就保存进哈希表
}
}
return {};
}
};
4.合并两个排序的链表
一看空间复杂度O(1),直接想到双指针。
代码详情:
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2) {
ListNode* head = new ListNode(INT_MIN); //创建一个空指针
ListNode* root = head; //记录根指针
while(pHead1 != nullptr && pHead2 != nullptr){
if (pHead1->val <= pHead2->val){ //链接小的那个指针
head->next = pHead1;
pHead1 = pHead1->next;
}
else{
head->next = pHead2;
pHead2 = pHead2->next;
}
head = head->next;
}
if(pHead1 == nullptr){ //剩下的指针直接链接在头指针后面
head->next = pHead2;
}
else{
head->next = pHead1;
}
return root->next; //空指针不返回
}
};
5. 用两个栈实现队列
栈是先进后出,而队列是先进先出,两个栈,一个负责进,一个负责出就能实现队列。
代码详情:
class Solution
{
public:
void push(int node) {
stack1.push(node); //压入进栈
}
int pop() {
if (stack2.empty() == true){ //出栈为空的时候,将进栈全部转入出栈
while(!stack1.empty()){
stack2.push(stack1.top());
stack1.pop();
}
}
int result = stack2.top(); //出栈不为空,先将出栈全部出完。
stack2.pop();
return result;
}
private:
stack<int> stack1; //stack1负责进栈
stack<int> stack2; //stack2负责出栈
};
6.跳台阶
最经典的动态规划题,就类似于斐波那契数列。
代码详情:
class Solution {
public:
int jumpFloor(int number) {
vector<int> dp(number + 1);
dp[0] = 0;
dp[1] = 1;
dp[2] = 2;
for(int i = 3;i<=number;++i){
dp[i] = dp[i-1] + dp[i-2]; //i就是前面两个相加
}
return dp[number];
}
};
7.链表中的节点每k个一组翻转
跟反转链表一样,但由于每k个反转,存在前后链表链接问题,处理好就不难。
代码详情:
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
class Solution {
public:
/**
*
* @param head ListNode类
* @param k int整型
* @return ListNode类
*/
ListNode* reverseKGroup(ListNode* head, int k) {
// write code here
ListNode* node = head;
for(int i = 0;i < k;++i){ //寻找k个链表
if (!node) return head; //不足k个不反转
node = node->next;
}
ListNode* res = reverse(head->next, head,node); //反转选中链表
head->next = reverseKGroup(node, k); //将下一部分链表进行链接
return res;
}
//反转函数
ListNode* reverse(ListNode* right,ListNode* left,ListNode* target){
ListNode* tem_right; //保存下一节点
while(right != target){
tem_right = right->next;
right->next = left;
left = right;
right = tem_right;
}
return left;
}
};
这题没自己写出来,反转后链表链接还是比较难写哈哈哈。
8.连续子数组的最大和
这道题好绕,想了好久都实现不出来,太可恶了。
代码详情:
class Solution {
public:
int FindGreatestSumOfSubArray(vector<int> array) {
if (array.size() == 1) return array[0]; //边界条件
int res = INT_MIN; //记录最终答案
int tem = 0; //记录相加大于零的连续子序列
for(int arr:array){
tem += arr;
res = max(res,tem);
if (tem < 0){ //如果小于零,舍弃前面数组
tem = 0;
}
}
return res;
}
};
9.最长无重复子数组
一开始有点没头绪,突然灵机一动,想到用哈希表存储遍历过的数据,当有重复的时候,从重复数据再来遍历就不会错过了,真是太机灵了我哈哈哈。
代码详情:
class Solution {
public:
/**
*
* @param arr int整型vector the array
* @return int整型
*/
int maxLength(vector<int>& arr) {
// write code here
unordered_map<int, int> map; //记录遍历过的数据,key为数据,value为下标
int res = 0; //存储最长长度
int tem = 0; //存储每次不重复数组长度
for(int i = 0;i < arr.size();++i){
if (map.count(arr[i])){ //判断是否重复
res = max(tem,res); //记录最大值
tem = 0;
i = map[arr[i]]; //将i更新为重复数据的下标
map.clear(); //清空哈希表
}
else{
map[arr[i]] = i;
tem++;
}
}
return max(res,tem);
}
};
10.判断链表中是否有环
之前写的时候很懵,但是看了解析,知道了为什么快慢指针可以判断出循环队列入口点。
靠,才发现这题只要是否有环。。。。想多了(可恶~~~)
代码详情:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode* slow = head,* fast = head;
do{
if (fast == nullptr || fast->next == nullptr){ //如果有空节点,代表无环
return false;
}
fast = fast->next->next; //快指针每次走两步
slow = slow->next; //慢指针只走一步,如果有环,快指针迟早追上慢指针
}while(slow != fast);
return true;
}
};
面试题(牛客网)
1.TCP和UDP区别;
TCP是基于字节的面向连接,可靠的传输控制协议,拥有流量控制和拥塞控制,支持点对点通信。
UDP是基于报文的无连接,不可靠的用户数据报协议。支持一对一,一对多,多对一,多对多通信
2.TCP三次握手四次挥手;
3.如果服务端先关闭连接会发生什么?
4.为什么会采用三次握手,若采用二次握手可以吗?
5.为什么会采用四次挥手,若采用三次挥手可以吗?
因为关闭连接时,server端收到客户端的FIN报文,并不会立即关闭socket,只能先回复一个ACK告诉client我已经收到你的关闭请求了,同时可能server还有数据没传输完,只有等server端数据传输完成了 才能发送FIN报文,所以这个地方要分两次发送,这样就有了四次挥手。
————————————————
版权声明:本文为CSDN博主「孤帆扁舟去」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42490152/article/details/100942319
6. 服务端的Time_Wait状态再哪个阶段出现?持续多久?为什么要设计这么一个状态?
Time_Wait阶段是最后阶段发送确认收到server端的fin报文释放连接请求后回复给server端ack报文,之后client端就进入Time_Wait阶段.
持续多久即是问为什么不马上关闭直接进入closed阶段,主要是考虑到网络的不可靠,假如client最后阶段发送给server端端ack报文由于网络原因丢失了server没收到呢,server端会重新发送fin报文过来,这个时候client端就要等. 等多久?等一个计时器时间2MSL,如果该时间段内再次收到server的fin报文 那client就必须回复. 如果没有收到,client就认为server端已经接收到了最后的ack报文.
————————————————
版权声明:本文为CSDN博主「孤帆扁舟去」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42490152/article/details/100942319
7.TCP如何实现可靠连接
8.解释TCP的滑动窗口如何实现,除了流量控制还有什么作用?
现在心态有点着急,太过急于求成了,我先自己静一静,好好整理一下计算机网络的知识。
分享一下今日投递趣事:
之前投递的公司没过,后面又发了一份,觉得奇怪打开一看红红的几款大字:昨日处理有误,我想这不是我有戏!!!结果仔细一看还是没过,梅开二度,靠。