C++编程
所有的代码在另一篇博文
TOPK问题(多种解法)
思路1:直接进行排序,输出最大的K个值即为TOPK(nlogn)
思路2:使用冒泡排序,K次冒泡之后,最大的即为数组后面K个元素(n*k)
思路3:维护一个大小为K小顶堆,将所给数组插入堆中,最后输出(nlog(k))判断链表是否有环,寻找链表环的起点
思路1:快慢指针,快指针步进2,慢指针步进1,如果有环,这两个指针必然相遇,将其中一个指针回归到链表的起点,另一个指针从当前位置继续前进,步进都为1,下次相遇即为环的起点。
循环队列
具体看代码
快速排序(存在问题如何优化)、归并排序、堆排序(注意时空复杂度、稳定性)
- 数据量比较小的情况下,可以采用插入排序替换快速排序
- 将重复数据划分到一起,下一次递归时不对重复数据进行递归排序
反转一个链表
首先定义一个虚拟头节点指向原链表,避免进行边界判断,之后定义一个指针,指向头节点,每次循环,记录当前指针的下一个指针,然后将当前指针的下一个指向pre 再将pre赋值为当前指针,最后将当前指针赋值为记录下来的下一个指针
归并链表
首先定义一个虚拟头节点,然后循环判断当前传入的链表是否为空,不为空的话,就比较当前两个结点值的大小,小的链接到新的链表后面,循环结束,将还没有遍历完的链表直接链接在新链表后面即可
并查集
首先将变量的father结点全部初始化为当前下标,使用时,判断是否是同一个集合只用判断他的father结点是否相同,查找时,只用查找他的father结点即可。
二叉树的公共祖先
如果两个结点存在公共祖先,必然存在:
- 两个结点分别在该公共祖先的左右子树
- 两个结点都在公共祖先的某一个子树
- 两个结点某一个在公共祖先的位置
- 当前结点是公共祖先,另一个结点在该结点的子树,或另一个结点不在当前子树
- 当前子树不包含给出的两个结点
二叉树的遍历(非递归/递归)
递归较简单,前序按照根=》左==》右、中序按照左=》根=》右、后序按照左=》右=》根的顺序进行递归输出即可。
非递归需要借助栈来实现,
- 如果当前节点不为空,访问节点,并且把节点进栈,循环条件为栈不空,取出栈顶元素,将结点放入答案数组,右孩子不空,压入右孩子,左孩子不空,压入左孩子。继续循环
- 从当前子树根结点出发,一直往左走,把沿途结点全部入栈,直到最左边,对于最左边的结点来说,他没有左孩子,根据“左根右”的顺序,这时需要从堆栈中弹出这个结点,访问它(这里表现为加到res数组中)如果它有右孩子,就往右边走,然后对于这棵子树重复上面的操作。
- 和前序反过来即可
数组的全排列
从给定数组从前往后依次枚举,每次选择一个没有用过的数字,选好之后,将该数字的状态改为“已被使用”,同时将该数字放到path里面,然后进行递归,当递归返回时,不要忘记将该数的状态改回“未被使用”,并将该数从相应位置上删除。当递归遇到当前path.size()等于nums.size()时,将path加入答案数组。
N个骰子出现和为m的概率
投一个骰子时,所有的点数出现的概率均为1/6,多加一颗骰子,概率应该是比当前骰子少一颗的所有骰子点数出现的次数和 除以6n,即状态转移方程dp[i][j] = dp[i - 1][j - 6] + dp[i - 1][j - 5] + dp[i - 1][j - 4] + dp[i - 1][j - 3] + dp[i - 1][j - 2] + dp[i - 1][j - 1],最后的dp[n][m] /6n即为n个骰子出现和为m的概率。
两个链表交汇的位置
C++基础问题
详细讲解智能指针的思想,循环引用,unique_ptr的实现原理
动态内存管理通常会出现两种问题,第一就是忘记释放内存,造成内存泄漏,第二就是尚有指针引用内存的情况下就释放了他,就会产生引用非法内存的指针,为了更安全的管理内存,引入了智能指针(栈上的对象),智能指针包含三种(shared_ptr,unique_ptr,weak_ptr)shared_ptr允许多个指针指向同一个对象,unque_ptr独占所指的对象