深信服面试常见算法题整理笔记
创始人
2024-04-22 03:07:09

⭐️我叫恒心,一名喜欢书写博客的研究生在读生。

原创不易~转载麻烦注明出处,并告知作者,谢谢!!!

这是一篇近期会不断更新的博客欧~~~ 有什么问题的小伙伴 欢迎留言提问欧。

在这里插入图片描述

文章目录

    • 1 反转链表
    • 2 排序
    • 3 设计LRU缓存结构
    • 4 最小K个数
    • 5 求二叉树的层次遍历
    • 6 **NC33** **合并两个排序的链表**
    • 7 **用两个栈实现队列**
    • 8 跳台阶
    • 9 求连续子数组的最大和
    • 10 判断一个链表是否有环
    • 11 删除链表倒数第K个节点(已经考了)
    • 12 大小端
    • 13 二叉树公共祖先
    • 14 二叉搜素树的公共祖先
    • 15 **字符串出现次数的TopK问题**
    • 16 加起来和位目标值的组合(二)
    • 17 连续子数组的最大乘积
    • 18 设计一个循环数组

1 反转链表

class Solution {
public:ListNode* ReverseList(ListNode* pHead) {ListNode* newHead = nullptr;while(pHead){ListNode* nex = pHead->next;pHead->next = newHead;newHead = pHead;pHead = nex;}return newHead;}
}

递归的形式

class Solution {public:ListNode* ReverseListCore(ListNode* node) {if (node == nullptr || node->next == nullptr) return node;ListNode* nexHead = node->next;ListNode* newHead = ReverseListCore(nexHead);nexHead->next = node;node->next = nullptr;return newHead;}ListNode* ReverseList(ListNode* pHead) {return  ReverseListCore(pHead);}
};

2 排序

堆排序

class Solution {
public:/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可* 将给定数组排序* @param arr int整型vector 待排序的数组* @return int整型vector*/void quickSort(vector& num, int begin, int end){if(begin > end) return ;int low = begin;int high = end;int key = num[begin];while(low < high){// 跟右边进行比较while(low < high && key <= num[high]){high--;}if(low < high) num[low++] = num[high];while(low < high && key >= num[low]){low++;}if(low < high) num[high--] = num[low];}num[low] = key;quickSort(num, begin, low-1);quickSort(num, low+1, end);}void heapfy(vector& arr, int i, int n){if(i >= n) return ;int c1 = 2*i + 1;int c2 = 2*i + 2;int max = i;if(c1 < n && (arr[c1] > arr[max])) max = c1;if(c2 < n && (arr[c2] > arr[max])) max = c2;if(max != i){swap(arr[max],arr[i]);heapfy(arr,max,n);}}void build_heap(vector& arr, int n){int parent = (n-2) / 2;for(int i = parent; i>=0; --i){heapfy(arr,i,n);}}void heapSort(vector& arr){int n = arr.size();build_heap(arr,n);for(int i = n-1; i >=0; --i){cout< MySort(vector& arr) {// write code here// 快速排序int n = arr.size();//quickSort(arr,0,n-1);heapSort(arr);return arr;}
};

3 设计LRU缓存结构

#include
#include 
#include
using namespace std;//这里放你的代码
struct DKLinkNode{int key,value;DKLinkNode* next;DKLinkNode* pre;DKLinkNode():key(0),value(0),pre(nullptr),next(nullptr){}DKLinkNode(int _key, int _val):key(_key),value(_val),pre(nullptr),next(nullptr){}
};class LRUCache {
private:// 借助哈希表来查询存储的位置,key value(链表节点)unordered_map cache;int capacity;int size;DKLinkNode* head;DKLinkNode* tail;
public:LRUCache(int _capacity):capacity(_capacity),size(0) {// 创建头尾 伪节点 便于定位head = new DKLinkNode();tail = new DKLinkNode();head->next = tail;tail->pre = head;}~LRUCache(){if(head != nullptr){delete head;head = nullptr;}if(tail != nullptr){delete tail;tail = nullptr;}for(auto& c : cache){if(c.second != nullptr){delete c.second;c.second = nullptr;}}}int get(int key) {// 如果双向链表中没有这个节点则直接返回if(!cache.count(key)){return -1;}// 如果有节点 则通过哈希表获取这个节点的地址,将这个节点移到前面DKLinkNode* node = cache[key];moveToHead(node);return node->value;}void put(int key, int value) {// 如果哈希表查找不到这个key 则插入新的值到哈希表中// 将新的值插入双向链表的头部if(!cache.count(key)){DKLinkNode* node = new DKLinkNode(key, value);cache[key] = node;addHeadNode(node);++size;// 如果当前的容量大于缓存的最大容量,则移除某段节点if(size > capacity){DKLinkNode* rNode = removeTail();cache.erase(rNode->key);delete rNode;--size;}}else{// 如果查找得到key,则将该节点移动到头部DKLinkNode* moveNode = cache[key];// 更新当前key对应的value 并移动链表moveNode->value = value;moveToHead(moveNode);}}void addHeadNode(DKLinkNode* node){node->pre = head;node->next = head->next;head->next->pre = node;head->next  = node;}void removeNode(DKLinkNode* rNode){rNode->pre->next = rNode->next;rNode->next->pre = rNode->pre;}DKLinkNode* removeTail(){DKLinkNode* rNode = tail->pre;removeNode(rNode);return rNode; }void moveToHead(DKLinkNode* node){// 删除当前节点removeNode(node);// 在头结点处添加进去addHeadNode(node);}
};int main(){LRUCache* cache = new LRUCache(2);cache->put(1, 1);cache->put(2, 2);int res = cache->get(1);       // 返回  1cout<put(3, 3);    // 该操作会使得密钥 2 作废res = cache->get(2);       // 返回 -1 (未找到)cache->put(4, 4);    // 该操作会使得密钥 1 作废res = cache->get(1);       // 返回 -1 (未找到)cout<get(3);       // 返回  3cout<get(4);       // 返回  4cout<

4 最小K个数

class Solution {
public:vector GetLeastNumbers_Solution(vector input, int k) {vector res;if(input.size() == 0 || k == 0) return res;// 利用最小堆来做。priority_queue, greater> minHeap;for(auto num : input){minHeap.push(num);}while(k--){res.push_back(minHeap.top());minHeap.pop();}return res;}
};

最小k个数 应该用大根堆来做

class Solution {
public:vector GetLeastNumbers_Solution(vector input, int k) {vector ret;if (k==0 || k > input.size()) return ret;priority_queue> pq;for (const int val : input) {if (pq.size() < k) {pq.push(val);}else {if (val < pq.top()) {pq.pop();pq.push(val);}}}while (!pq.empty()) {ret.push_back(pq.top());pq.pop();}return ret;}
};

5 求二叉树的层次遍历

/*** struct TreeNode {*  int val;*  struct TreeNode *left;*  struct TreeNode *right;* };*/class Solution {public:/**** @param root TreeNode类* @return int整型vector>*/vector > levelOrder(TreeNode* root) {// write code herevector> res;if (root == nullptr) return res;queue q;q.push(root);while (!q.empty()) {int q_size = q.size();vector temp;while (q_size--) {TreeNode* node = q.front();temp.push_back(node->val);q.pop();if (node->left) q.push(node->left);if (node->right) q.push(node->right);}res.push_back(temp);}return res;}
};

6 NC33 合并两个排序的链表

class Solution {
public:ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {if(l1 == nullptr) return l2;if(l2 == nullptr) return l1;ListNode* dummy = new ListNode(0);ListNode* cur = dummy;while(l1 && l2){if(l1->val <= l2->val){cur->next = l1;cur = l1;l1 = l1->next;}else if(l1->val > l2->val){cur->next = l2;cur = l2;l2 = l2->next;}}if(l1!=nullptr){cur->next = l1;}else if(l2 != nullptr){cur->next = l2;}return dummy->next;}
};

7 用两个栈实现队列

class Solution
{
public:void push(int node) {stack1.push(node);}int pop() {// 借助辅助栈完成 while(!stack1.empty()){stack2.push(stack1.top());stack1.pop();}int val = stack2.top();stack2.pop();while(!stack2.empty()){stack1.push(stack2.top());stack2.pop();}return val;}private:stack stack1;stack stack2; // 辅助栈
};

8 跳台阶

class Solution {
public:int jumpFloor(int n) {// 跳台阶的动态规划vector dp(n+1,0);dp[0] = 1;for(int i = 1; i <= n; ++i){for(int j = 1; j <=2; ++j){if(i - j >= 0) dp[i] += dp[i - j];}}return dp[n];}
};

9 求连续子数组的最大和

时间复杂度 O(n)

class Solution {
public:int FindGreatestSumOfSubArray(vector array) {// 动态规划 dp[i] 表示添加i个数组后 最大和if(array.size() == 1) return array[0];int res = array[0];int n = array.size();vector dp(n+1,0);dp[0] = array[0];for(int i = 1; i < array.size(); ++i){dp[i] = max(dp[i-1]+array[i], array[i]);res = max(res, dp[i]);}return res;}
};

优化空间复杂度

class Solution {
public:int FindGreatestSumOfSubArray(vector array) {int sum = 0;int maxVal = array[0];for(int i = 0; i < array.size(); ++i){sum = max(sum + array[i], array[i]);maxVal = max(sum, maxVal);}return maxVal;}
};

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) {// 特殊情况 当链表长度为空为1无环// 有环 必然会相遇// 无环 则必然会遇到空节点if(head == nullptr || head->next == nullptr){return false;}ListNode* fast = head->next;ListNode* slow = head;while(fast->next!=nullptr && fast->next->next!=nullptr){if(slow == fast){return true;}else{fast = fast->next->next;slow = slow->next;}}return false;}
};

11 删除链表倒数第K个节点(已经考了)

class Solution {
public://求链表的长度int len(ListNode* head){int s=0;while(head!=NULL){s++;head=head->next;}return s;}ListNode* removeNthFromEnd(ListNode* head, int n) {ListNode* pre=head;int k=len(pre)-n;//要是之间是删除的是头节点 直接指针后移if(k==0){return head->next;}for(int i=0;inext;}//越过删除的结点pre->next=pre->next->next;return head;}
};

12 大小端

#include
using namespace std;
int main(){union{int num;char lowC;}data;data.num = 1;if(data.lowC == 1){cout<<"small "<

13 二叉树公共祖先

class Solution {
public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {if (root == q || root == p || root == NULL) return root;TreeNode* left = lowestCommonAncestor(root->left, p, q);TreeNode* right = lowestCommonAncestor(root->right, p, q);if (left != NULL && right != NULL) return root;if (left == NULL && right != NULL) return right;else if (left != NULL && right == NULL) return left;else  { //  (left == NULL && right == NULL)return NULL;}}
};

14 二叉搜素树的公共祖先

解题思路: 公共祖先必然是再左右节点之间 [p,q]

class Solution {
public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {if (root->val > p->val && root->val > q->val) {return lowestCommonAncestor(root->left, p, q);} else if (root->val < p->val && root->val < q->val) {return lowestCommonAncestor(root->right, p, q);} else return root;}
};
class Solution {
public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {while(root) {if (root->val > p->val && root->val > q->val) {root = root->left;} else if (root->val < p->val && root->val < q->val) {root = root->right;} else return root;}return NULL;}
};

15 字符串出现次数的TopK问题

自定义小堆

struct cmp {bool operator() (pair &p1, pair &p2) {return p1.second > p2.second || (p1.second == p2.second && p1.first < p2.first); //出现次数较高或者出现次数相同字典序小的优先级高(堆顶的元素优先级最低)}
};
class Solution {
public:vector > topKstrings(vector& strings, int k) {vector > res;unordered_map umap; //用于统计字符串出现次数for(string &s: strings) umap[s]++; priority_queue, vector >, cmp> pq; //自定义优先队列for(auto it = umap.begin(); it != umap.end(); it++) { //遍历无序mapif(pq.size() < k) pq.emplace(pair {it->first, it->second}); //当堆元素数小于k直接入堆else if(it->second > pq.top().second || (it->second == pq.top().second && it->first < pq.top().first)) { //否则判断是否能取出堆顶放入新元素pq.pop();pq.emplace(pair {it->first, it->second});}}while(!pq.empty()) { //由优先级从小到大依次取出res.emplace_back(vector {pq.top().first, to_string(pq.top().second)});pq.pop();}reverse(res.begin(), res.end()); //逆转使优先级从大到小return res; //返回结果}
};

16 加起来和位目标值的组合(二)

class Solution {public:void dfs(vector& num, int target, vector >& res,vector& tmp, int start) {if (target == 0) {res.push_back(tmp);return;}if (start >= num.size()) return;for (int i = start; i < num.size(); ++i) {if (i > start && num[i] == num[i - 1]) continue;// 剪枝//前面的排序就有意义了 这块要是剩余的num[i]的值已经大于target的大小 后面已经是无效搜索了if (num[i] <= target ) {tmp.push_back(num[i]);dfs(num, target - num[i], res, tmp,i + 1);tmp.pop_back();}}}vector > combinationSum2(vector& num, int target) {vector > res;vector tmp;if (num.empty()) return res;sort(num.begin(), num.end());dfs(num, target, res, tmp, 0);return res;}
};

17 连续子数组的最大乘积

class Solution {
public:/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可* @param nums int整型vector* @return int整型*/int maxProduct(vector& nums) {vector pos(nums); // 存储以nums[i] 结尾的最大乘积vector neg(nums); // 存储以 nums[i] 结尾的最小乘积int result=nums[0];for(int i=1;i

18 设计一个循环数组

class MyCircularQueue {
private:int front;int tail;int capity;vector element;
public:MyCircularQueue(int k) {this->capity = k + 1;front = tail = 0;this->element = vector(capity);}bool enQueue(int value) {if(isFull()){return false;}element[tail] = value;tail = (tail + 1) % capity;return true;}bool deQueue() {if(isEmpty()){return false;}front = (front + 1) % capity;return true;}int Front() {if(isEmpty()){return -1;}return element[front];}int Rear() {if(isEmpty()){return -1;}return element[(tail -1 + capity) % capity];}bool isEmpty() {return front == tail;}bool isFull() {return front == (tail + 1) % capity;}
};/*** Your MyCircularQueue object will be instantiated and called as such:* MyCircularQueue* obj = new MyCircularQueue(k);* bool param_1 = obj->enQueue(value);* bool param_2 = obj->deQueue();* int param_3 = obj->Front();* int param_4 = obj->Rear();* bool param_5 = obj->isEmpty();* bool param_6 = obj->isFull();*/

最后 🐶狗头保命

一名喜欢书写博客的研究生在读生

如果觉得有用,麻烦三连支持一下欧,希望这篇文章可以帮到你,你的点赞是我持续更新的动力

相关内容

热门资讯

北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...