【408数据结构】备考常见必会算法图鉴
408算法题
提示:代码C++,部分引用自leetcode
文章目录
- 408算法题
- 一、链表
- 1.1链表逆置
- 1.2删除链表倒数第n个结点
- 1.3 给定两个增序的链表,试将其合并成一个增序的链表。
- 1.4 删除有序(递增)链表中的重复元素。
- 1.5 以 O(1) 的空间复杂度,判断链表是否回文。
- 1.6 已排序链表,删除所有重复元素(保留一个)
- 1.7 给定两个链表,判断它们是否相交于一点,并求这个相交节点。
- 二、栈与队列
- 三、树与二叉树
- 3.1 [递归]二叉树的深度
- 3.2 [递归][树的判定]翻转平衡二叉树
- 3.3 [递归][树的判定]平衡二叉树的判定
- 3.4 [递归]二叉树的直径
- 3.5 [双递归]二叉树的路径总和
- 3.6 [递归]判断一个二叉树是否对称
- 3.7 [遍历][递归]二叉树的前中后序遍历
- 3.8 [遍历][迭代]二叉树的前序遍历
- 3.9 [遍历]二叉树的层序遍历
- 四、图(考的较少)
- 五、排序
- 5.1 [插入类]直接插入排序
- 5.2 [插入类]希尔排序
- 5.3 [交换类]冒泡排序
- 5.3 [交换类]快排
- 5.4 [选择类]简单选择
- 5.5 归并排序(个人觉得会考)
- 总结
提示:以下是本篇文章正文内容,下面案例可供参考
一、链表
1.1链表逆置
方法1.迭代
class Solution {public:ListNode* reverseList(ListNode* head) {ListNode* prev = nullptr;ListNode* curr = head;while (curr) {ListNode* next = curr->next;curr->next = prev;prev = curr;curr = next;}return prev;}
};
方法2.递归
class Solution {public:ListNode* reverseList(ListNode* head) {if (!head || !head->next) {return head;}ListNode* newHead = reverseList(head->next);head->next->next = head;head->next = nullptr;return newHead;}
};
1.2删除链表倒数第n个结点
方法1:双指针,使用快慢指针
//哑结点其实就是放在第一个存放数据结点之前、头结点之后的结点。加入哑结点之后就可以使所有数据结点都有前驱结点,这样就会方便执行链表的一些操作(比如删除)
class Solution {public:ListNode* removeNthFromEnd(ListNode* head, int n) {//在头结点之前设置哑结点ListNode* dummy = new ListNode(0, head);ListNode* first = head;//慢的用哑结点赋值,与快的同步往后会相差一位 便于删除ListNode* second = dummy;for (int i = 0; i < n; ++i) {first = first->next;}while (first) {first = first->next;second = second->next;}second->next = second->next->next;ListNode* ans = dummy->next;delete dummy;return ans;}
};
1.3 给定两个增序的链表,试将其合并成一个增序的链表。
样例
Input: 1->2->4, 1->3->4
Output: 1->1->2->3->4->4
方法1:递归
class Solution {public:ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {if (l1 == nullptr) {return l2;} else if (l2 == nullptr) {return l1;} else if (l1->val < l2->val) {l1->next = mergeTwoLists(l1->next, l2);return l1;} else {l2->next = mergeTwoLists(l1, l2->next);return l2;}}
};
方法2:迭代
class Solution {public:ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {ListNode* preHead = new ListNode(-1);ListNode* prev = preHead;while (l1 != nullptr && l2 != nullptr) {if (l1->val < l2->val) {prev->next = l1;l1 = l1->next;} else {prev->next = l2;l2 = l2->next;}prev = prev->next;}// 合并后 l1 和 l2 最多只有一个还未被合并完,我们直接将链表末尾指向未合并完的链表即可prev->next = l1 == nullptr ? l2 : l1;return preHead->next;}
};
1.4 删除有序(递增)链表中的重复元素。
leetcode:83
输入:head = [1,1,2]
输出:[1,2]
class Solution {public:ListNode* deleteDuplicates(ListNode* head) {if (!head) {return head;}ListNode* cur = head;while (cur->next) {if (cur->val == cur->next->val) {cur->next = cur->next->next;}else {cur = cur->next;}}return head;}
};
1.5 以 O(1) 的空间复杂度,判断链表是否回文。
leetcode:234
输入:head = [1,2,2,1]
输出:true
方法1:非O(1)
借助辅助栈,将链表值放入栈中,遍历看两个值是否相等
//借用辅助栈
class Solution {public:bool isPalindrome(ListNode* head) {ListNode* cur = head;stack<int> s;while (cur){s.push(cur->val);cur = cur->next;}while (!s.empty()){if (s.top() != head->val)return false;s.pop();head = head->next;}return true;}
};
方法2:递归 递归也不满足O(1)
方法3:双指针
使用快慢指针找到中点,后半段翻转,看是否相同
class Solution {public:
// 主函数bool isPalindrome(ListNode* head) {if (!head || !head->next) {return true; }ListNode *slow = head, *fast = head;while (fast->next && fast->next->next) {slow = slow->next;fast = fast->next->next;}//由于链表的长度有奇数和偶数之分//在奇数时slow在中间//偶数时slow在中间两个数的第一个//所以他们需要翻转后续的结点slow = reverseList(slow->next);while (slow) {if (head->val != slow->val){return false; } head = head->next;slow = slow->next;}return true; } //逆置ListNode* reverseList(ListNode* head) {ListNode *prev = nullptr, *next;while (head) {next = head->next;head->next = prev;prev = head;head = next;}return prev;}
};
1.6 已排序链表,删除所有重复元素(保留一个)
Leeetcode 83
class Solution {public:ListNode* deleteDuplicates(ListNode* head) {if (!head) {return head;}ListNode* cur = head;while (cur->next) {if (cur->val == cur->next->val) {cur->next = cur->next->next;}else {cur = cur->next;}}return head;}
};
1.7 给定两个链表,判断它们是否相交于一点,并求这个相交节点。
a+b+c = a+c+b
class Solution {public:ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {if (headA == nullptr || headB == nullptr) {return nullptr;}ListNode *pA = headA, *pB = headB;while (pA != pB) {pA = pA == nullptr ? headB : pA->next;pB = pB == nullptr ? headA : pB->next;}return pA;}
};
二、栈与队列
栈与队列一般不作为单独算法考点,只会以辅助栈和辅助队列的形式出现,算法不予以统计
三、树与二叉树
3.1 [递归]二叉树的深度
class Solution{public:int maxDepth(TreeNode* root){return 1+man(maxDepth(root->left),maxDepth(root->right)):0;}
};
3.2 [递归][树的判定]翻转平衡二叉树
class Solution {public:TreeNode* invertTree(TreeNode* root) {if (root == nullptr) {return nullptr;}TreeNode* left = invertTree(root->left);TreeNode* right = invertTree(root->right);root->left = right;root->right = left;return root;}
};
3.3 [递归][树的判定]平衡二叉树的判定
Leetcode
概念:左右子树高度差小于等于1
思路:类似于求树的深度,但有两个不同的地方:一是我们需要先处理子树的深度再进行
比较,二是如果我们在处理子树时发现其已经不平衡了,则可以返回一个-1。
class Solution {public:int height(TreeNode* root) {if (root == NULL) {return 0;} else {return max(height(root->left), height(root->right)) + 1;}}bool isBalanced(TreeNode* root) {if (root == NULL) {return true;} else {//当前结点的左右平衡因子小于等于1,递归判断其左右子树是否满足平衡二叉树return abs(height(root->left) - height(root->right)) <= 1 && isBalanced(root->left) && isBalanced(root->right);}}
};
3.4 [递归]二叉树的直径
Leetcode
注意 int&的用法
class Solution {public:int diameterOfBinaryTree(TreeNode* root) {int diameter = 0;helper(root, diameter);return diameter;}//辅助函数 注意int& 转为引用类型,使得实参双向传递int helper(TreeNode* node,int& diameter){//终止条件if(node == nullptr)return 0;//返回左右子树的高度int l = helper(node->left, diameter);int r = helper(node->right, diameter);//比较此时左右子树的和与最大值的大小diameter = max(l + r, diameter);return max(l, r) + 1; }
};
3.5 [双递归]二叉树的路径总和
Leetcode
给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。
辅助函数:计算连续加入节点的路径。
class Solution {public:int pathSum(TreeNode* root, int targetSum) {return root==nullptr?0:dfs(root,targetSum)+dfs(root->left,targetSum)+dfs(root->right,targetSum);}int dfs(TreeNode* root, int targetSum){if(!root)return 0;//注意此时相等不能返回,int count = (root->val == targetSum)? 1: 0;count+=dfs(root->left,targetSum-root->val);count+=dfs(root->right,targetSum-root->val);return count;}};
3.6 [递归]判断一个二叉树是否对称
辅助函数:判断两棵子树是否相等
“四步法”:
(1)如果两个子树都为空指针,则它们相等或对称
(2)如果两个子树只有一个为空指针,则它们不相等或不对称
(3)如果两个子树根节点的值不相等,则它们不相等或不对称
(4)根据相等或对称要求,进行递归处理。
class Solution {public:bool check(TreeNode *p, TreeNode *q) {if (!p && !q) return true;if (!p || !q) return false;return p->val == q->val && check(p->left, q->right) && check(p->right, q->left);}bool isSymmetric(TreeNode* root) {return check(root, root);}
};
3.7 [遍历][递归]二叉树的前中后序遍历
class Solution {public://前序void preorder(TreeNode *root, vector<int> &res) {if (root == nullptr) {return;}res.push_back(root->val);preorder(root->left, res);preorder(root->right, res);}//中序void inorder(TreeNode* root, vector<int>& res) {if (!root) {return;}inorder(root->left, res);res.push_back(root->val);inorder(root->right, res);}//后序void aftorder(TreeNode *root, vector<int> &res) {if (root == nullptr) {return;}aftorder(root->left, res);aftorder(root->right, res);res.push_back(root->val);}vector<int> inorderTraversal(TreeNode* root) {vector<int> res;inorder(root, res);return res;}
};
3.8 [遍历][迭代]二叉树的前序遍历
借助辅助栈
class Solution {public:vector<int> preorderTraversal(TreeNode* root) {vector<int> res;if (root == nullptr) {return res;}stack<TreeNode*> stk;TreeNode* node = root;while (!stk.empty() || node != nullptr) {while (node != nullptr) {res.emplace_back(node->val);stk.emplace(node);node = node->left;}node = stk.top();stk.pop();node = node->right;}return res;}
};
3.9 [遍历]二叉树的层序遍历
借助辅助队列 BFS
class Solution {public:vector<vector<int>> levelOrder(TreeNode* root) {vector <vector <int>> ret;if (!root) {return ret;}queue <TreeNode*> q;q.push(root);while (!q.empty()) {int currentLevelSize = q.size();ret.push_back(vector <int> ());for (int i = 1; i <= currentLevelSize; ++i) {auto node = q.front(); q.pop();ret.back().push_back(node->val);if (node->left) q.push(node->left);if (node->right) q.push(node->right);}}return ret;}
};
四、图(考的较少)
五、排序
5.1 [插入类]直接插入排序
void InsertSort(int arr[], int n){int i, j, temp;//遍历数组for (i = 1; i < n; i++){//当前元素的前驱大于当前元素if (arr[i - 1] > arr[i]) {//保存arr[i]temp = arr[i];//将前面有序序列中的所有大于arr[i]的值全部后移一位for (j = i - 1; j >= 0 && arr[j] > temp; j--){arr[j + 1] = arr[j];}//将原arr[i]赋值给arr[j + 1]arr[j + 1] = temp;}//if}//for
}
5.2 [插入类]希尔排序
void ShellSort(int arr[], int n) {int d;//初始化d为n/2,每一轮d为上一轮的1/2for (d = n / 2; d >= 1; d /= 2) {//从每个个分组的第二个元素开始,遍历剩余元素,进行直接插入排序for (int i = 1 + d; i < n; i++) {//直接插入排序(组间元素对比)if (arr[i] < arr[i - d]) {arr[0] = arr[i];int j;for (j = i - d; j > 0 && arr[j] > arr[0]; j -= d) {arr[j + d] = arr[j];}arr[j + d] = arr[0];}}}
}
5.3 [交换类]冒泡排序
//交换
void swap(int &a, int &b) {int temp = a;a = b;b = temp;
}
//冒泡排序
void BubbleSort(int arr[], int n) {for (int i = 0; i < n - 1; i++) {//标记此轮循环中是否进行了交换bool flag = false;//每次从数组中最后一个元素向前遍历,直到第i个元素for (int j = n - 1; j >= i; j--) {//将相邻两个逆序元素交换为正序,并更改flagif (arr[j - 1] > arr[j]) {swap(arr[j - 1], arr[j]);flag = true;}}//for//此次循环元素都是正序,则结束函数if (!flag) return;}//for
}
5.3 [交换类]快排
分治法
void QuickSort(vector<int>& v, int low, int high)
{if (low >= high) // 结束标志return;int first = low; // 低位下标int last = high; // 高位下标int key = v[first]; // 设第一个为基准while (first < last){// 将比第一个小的移到前面while (first < last && v[last] >= key)last--;if (first < last)v[first++] = v[last];// 将比第一个大的移到后面while (first < last && v[first] <= key)first++;if (first < last)v[last--] = v[first];}// 基准置位v[first] = key;// 前半递归QuickSort(v, low, first - 1);// 后半递归QuickSort(v, first + 1, high);
}
5.4 [选择类]简单选择
//交换元素
void swap(int &a, int &b){int temp = a;a = b;b = temp;
}//简单选择排序
void SelectSort(int arr[], int n){//遍历数组for (int i = 0; i < n; i++){//标记当前数组中最小值元素的下标,初始为第 i 个元素int min = i;//从i + 1开始遍历数组for (int j = i + 1; i < n; j++){if (arr[j] < arr[min]) min = j;}//交换第 i 个元素和最小值元素swap(arr[i] , arr[j]);}
}
5.5 归并排序(个人觉得会考)
leetcode
在这里插入代码片
总结
【408数据结构】备考常见必会算法图鉴相关推荐
- 前端必会算法——线性数据结构的递归遍历
上一篇: 前端必会算法--线性数据结构的遍历 线性数据结构的递归遍历 数组是知道长度的,最好的遍历方式的循环 var arr = [1,2,3,4]; //循环遍历数组,常见,常用 function ...
- 数据结构 - 二叉树 - 面试中常见的二叉树算法题
数据结构 - 二叉树 - 面试中常见的二叉树算法题 数据结构是面试中必定考查的知识点,面试者需要掌握几种经典的数据结构:线性表(数组.链表).栈与队列.树(二叉树.二叉查找树.平衡二叉树.红黑树).图 ...
- 数据结构 - 链表 - 面试中常见的链表算法题
数据结构 - 链表 - 面试中常见的链表算法题 数据结构是面试中必定考查的知识点,面试者需要掌握几种经典的数据结构:线性表(数组.链表).栈与队列.树(二叉树.二叉查找树.平衡二叉树.红黑树).图. ...
- 【数据结构---排序】庖丁解牛式剖析常见的排序算法
排序算法 一.常见的排序算法 二.常见排序算法的实现 1. 直接插入排序 2. 希尔排序 3. 直接选择排序 4. 堆排序 5. 冒泡排序 6. 快速排序 6.1 递归实现快速排序 思路一.hoare ...
- 机械转码日记【5】《数据结构》常见排序算法及对比(第一次画动图)
目录 前言 1.冒泡排序 2.直接插入排序 3.希尔排序 4.直接选择排序 5.堆排序 6.快速排序 6.1将区间按照基准值划分为左右两半部分的常见方式 6.1.1Hoare版本 6.1.2挖坑法 6 ...
- access两字段同时升序排序_7 天时间,我整理并实现了这 9 种常见的排序算法
排序算法 回顾 我们前面已经介绍了 3 种最常见的排序算法: java 实现冒泡排序讲解 QuickSort 快速排序到底快在哪里? SelectionSort 选择排序算法详解(java 实现) 然 ...
- 力扣高频算法php_互联网公司最常见的面试算法题有哪些?
很多时候,你即使提前复习了这些最常见的面试算法题,你依旧无法通过算法面试! 为什么?你在提前准备复习的时候,在网上找了半天相应题目的分析文章,但你看了就是不懂. 你在面试的时候,卡壳了,一时间忘了怎么 ...
- python常用算法有哪些_python常见的排序算法有哪些?
大家都知道,关于python的算法有很多,其中最为复杂的就是python的排序算法,因为它并不是单一的,而是复杂的,关于排序算法就有好几种不同的方式,大家可以根据以下内容,结合自己的项目需求,选择一个 ...
- 常见的GC算法(GC的背景与原理)
常见的GC算法(GC的背景与原理) GC 是英文词汇Garbage Collection的缩写,中文一般直译为 "垃圾收集".当然也会说 "垃圾回收". 三种垃 ...
最新文章
- 图像配准----Harris算子
- 鸿洋android屏幕适配四部曲-传送门
- java web nodejs_我的2013--从java web到nodejs
- [渝粤教育] 西南科技大学 动态网页设计(JSP) 在线考试复习资料
- UVA 116——Unidirectional TSP
- PJSIP UA分析(2)--PJSUA注册
- 随机名字生成小demo源码
- java名人_识别名人 · Find the Celebrity
- python 字符串不区分大小写_还在吐槽文本字符串难以处理,Python的这个绝活你还不知道
- Android 屏幕适配攻略(四)获取手机屏幕的相关信息 与动态设置控件的大小
- epoll示例程序——服务端
- JavaScript 基础(十六):Navigator对象
- [面试] 算法(八)—— 树
- 数据分析好学吗_数据分析篇 | 一个虎扑社区数据分析实战
- python 文本处理---英文文本预处理(简单易懂 全有注释)!!!!!使用正则表达式以及nltk库分词器双方法!
- 使用Python给罗永浩生成卡通头像
- Spring Cloud Gateway编码实现任意地址跳转
- 原生js高仿浏览器ctrf+f
- BGP高防服务器与普通高防服务器有什么区别?
- Lumerical---FDE中的金属边界条件仿真
热门文章
- 搭建K8S 的dashboard的坑the server could not find the requested resource
- 【数据结构和算法】赫夫曼树 | 实战演练(二)
- pcf8563c语言程序,PCF8563实时时钟C源程序
- 星巴克招人!要技术大拿。
- 修复花雨庭服务器,我的世界手机版怎么进花雨庭服务器 | 手游网游页游攻略大全...
- 练习2-6 编写一个函数setbits(x, p ,n, y),该函数返回对x执行下列操作后的结果值: 将x中从第p位开始的n个(二进制)位设置为y中最右边n位的值,x的其余各位保持不变。
- VMware虚拟机硬盘大小修改
- STM32学习心得十八:通用定时器基本原理及相关实验代码解读
- XTU Oj 128
- html格式显示图标异常,HTM或HTML图标变成无法显示和识别的解决方法大全