数据结构和数据库的区别
- 他们两个本质在于存储管理数据
- 数据结构--在内存中存储管理数据
- 数据库--在磁盘中存储管理数据
为什么现在越来越不关心内存,而关心运行速度(时间复杂度)
- 摩尔定律表示:集成电路上可以容纳的晶体管数目在大约每经过18个月便会增加一倍
- 因为存在摩尔定律,所以随着时间的推移,内存会越来越大
1.消失的数字
思路一:映射
- malloc一个全是-1的新数组
- 遍历这些数字,这个数是多少,就写到新数组对应的位置
- 遍历一遍新数组,那个位置是-1,它的下标就是缺失的数字
思路二:异或(推荐)
- 异或时,一个数字异或它自己结果为0,一个数字异或0结果是它自己
- 其他数出现两次,只有缺失的那个数字出现一次
思路三:排序+二分查找(不推荐)
- 虽然二分查找的时间复杂度是O(logN),但是二分查找使用的前提是在有序的情况下
- 对于排序,即使用了快排,时间复杂度也是O(N*logN)
思路四:公式法
- 求和计算,两者一减得到的就是那个缺失的数字
2.轮转数组
思路一:直接旋转
- 每次旋转一个,旋转k次
- 时间复杂度为O(N*k),空间复杂度O(1)
思路二:以空间换时间
-
开辟一段新的空间,先把数组后k个数放入新空间,再把n-k个数放入新空间,最后拷贝回去
-
时间复杂度为O(N),空间复杂度O(N)
思路三:三步翻转法(推荐)
- 前n-k个逆置,后k个逆置,整体逆置
- 时间复杂度O(N),空间复杂度O(1)
3.移除元素
思路一:覆盖删除
- 先找到val,并将val之后的数从后向前覆盖
- 时间复杂度O(N^2)
思路二: 空间换时间
- 保留不是val的值,将这些值拷贝到一个新数组
- 时间复杂度O(N),空间复杂度O(N)
思路三:双指针
- src所指向的值不等于val时,将src所指向的值赋值给des所指向的值,然后src++,des++
- src所指向的值等于val时,只让src++
4.删除有序数组中的重复项
- 去重算法,使用的是前后指针:
5.合并两个有序数组
- 从后向前进行比较,然后归并
6.移除链表元素
思路一: 直接移除
- 情况有点多,需要考虑全面
思路二:头插
- 注意最后需要释放头结点,把头节点置为空
7.反转链表
思路一:翻指针
思路一:头插
- 注意最后需要释放头结点,把头节点置为空
8.链表的中间节点
- 这里运用了快慢指针
9.链表中倒数第k个结点
- 这里还是用的快慢指针,只不过这里是快慢指针的一种变形,
- fast是从头节点的k个节点开始,
- 注意考虑要全面
10.合并两个有序链表
- 这里运用了哨兵位,带头节点
11.链表分割
- 一个链表存比x大的,另一个链表存比x小的,
12链表的回文结构
- 找中间节点,逆置,比较
13.相交链表
- 这里需要先让长的那个链表先走(两个链表长度只差)
- 时间复杂度为O(N),设计的十分巧妙
14.判断是否为环形链表
请证明slow一次走一步,fast一次走两步,一定能追上
- 设环的长度为C
- slow刚进环的时候,fast就开始追,假设从fast开始到slow之间的距离是N(0<=N<C)
- 因为fast比slow多走一步,那么他们之间的距离就会不断的减一
- 从fast开始到slow之间的距离:N N-1 N-2 N-3 N-4 .....0
- 从fast开始到slow之间的距离变成0,意味着fast追上slow,相遇了
请证明slow一次走一步,fast一次走三步,不一定能追上,甚至会死循环
- 设环的长度为C
- slow刚进环的时候,fast就开始追,假设从fast开始到slow之间的距离是N(0<=N<C)
- 因为fast比slow多走一步,那么他们之间的距离就会不断的减二
- 当N为偶数时,从fast开始到slow之间的距离:N N-2 N-4 N-6 .....0
从fast开始到slow之间的距离变成0,意味着fast追上slow,相遇了 - 当N为奇数时,从fast开始到slow之间的距离:N N-2 N-4 N-6 .....-1
从fast开始到slow之间的距离变成-1,意味着fast追上且超过了slow,
此时从fast开始到slow之间的距离变成了C-1 - 当C-1为偶数时,从fast开始到slow之间的距离:C-1 C-3 C-5 C-7....0
从fast开始到slow之间的距离变成0,意味着fast追上slow,相遇了 - 当C-1为奇数时,从fast开始到slow之间的距离:C-1 C-3 C-5 C-7....-1
从fast开始到slow之间的距离变成-1,意味着fast追上且超过了slow,
此时从fast开始到slow之间的距离变成了C-1,如果到了这一步就意味着已经确定了C-1是奇数
之后从fast开始到slow之间的距离将用永远不会为0,意味着死循环
15. 求环形链表的入口点
思路一:数学推导
当这个链表是环形链表时
- slow从开始到与fast相遇点meet走过的路程为S1=L+x
- fast从开始到与slow相遇点meet走过的路程为S2=L+x+N*C
- fast的速度是slow的两倍,由2*S1=S2得,L=N*C-x,化简为L=(N-1)*C+y
- (N-1)*C意味着位置没有变,在原地转圈
- 综上诉述L=y
注意:slow指针进环之前,fast有可能在环里面转了N圈,这跟L(入环前的长度有关),也与C(环的长度有关),所以才有S2=L+x+N*C中的N*C
结论:一个指针从meet点开始走,一个指针从链表开始走他们会在入口点相遇
思路二:转换
- 一个指针从slow和fast相遇点开始,另一个指针从head开始
- 原问题转换成求两个链表的相交节点
16.复制带随机指针的链表
- 设计要点:node->random = cur->random->next;
17.有效括号
- 左括号入栈,如果是右括号,则将栈顶的元素进行判断
- 需要特别注意:只有一个括号,栈是否为空都需要考虑
18.用队列实现栈
- 利用队列的特性进行解决
- 两个队列相互交换
19.用栈实现队列
- 利用栈的特性进行解决
- 两个栈进行交换
20.设计循环队列
- 数组支持下标访问,这里多开了一个空间,使判断队列是否满更加简单
- 开空间的时候注意括号,
21.单值二叉树
- 利用二叉树的前中后序
- 注意节点为空的情况
22.相同的树
- 利用二叉树的前中后序
- 注意节点为空的情况
23.对称二叉树
- 借用上面相同的树的代码
- 注意节点为空的情况
24.另一颗数的子树
- 利用二叉树的前中后序
- 借用上面相同的树的代码
- 注意节点为空的情况
25.二叉树的前序遍历
- 形参是实参的临时拷贝,传地址
26.二叉树的中序遍历
- 与二叉数的前序遍历同理
27.二叉数的后序遍历
- 与二叉数的前序遍历同理
28.二叉树遍历
- 先用前序构建树,
29.二叉树的最大深度
- 通过分治思想,结合后序,递归解决
30.平衡二叉数
- 两层递归解决
31.二叉树的层序遍历
- 重点在于returnColumnSizes,他的每一个行都是需要开辟空间的
32.迷宫问题
![](https://img-blog.csdnimg.cn/97548e302822402da612b19c3fdf308b.png)
二叉树进阶
1.根据二叉树创建字符串
- 节点的左子树为空,右子树不为空,这种情况的()就不能省略
- 节点的左子树为不为空,右子树为空,这种情况的()就能省略
- 节点的左子树为为空,右子树为空,这种情况的()就能省略
2.二叉树的层序遍历
- _levelSize控制每一层的个数
3.二叉树的层序遍历2
- 先正向遍历,再通过reserve进行逆置
4.二叉树的最近公共祖先
- 用DFS遍历,再用stack存路径,最后使用回溯
5.二叉搜索树与双向链表
- 中序得到cur,通过prev = cur不断的使prev移动
- 这里的prev只用一份,所以要用引用
6.从前序与中序遍历序列构造二插树
- 前序得到根
- 中序得到根的左右子树,控制左右区间的范围,
7. 二叉树的前序遍历(非递归)
- 开始访问一颗树(v.push_back(cur->val);st.push(cur);),
- 先访问左路节点,再访问左路节点的右子树
- st.top();一个节点中栈里面出来意味着:这个节点级它的左子树访问完了,还剩右子树
-
while(cur || !st.empty()),访问最左节点时触发cur,第一个根节点的左子树访问完了,要访问右子树时触发!st.empty()
8.二叉树的中序遍历(非递归实现)
- 中序遍历和前序遍历类似,只不过访问v.push_back(cur->val)记录节点的时间不同
9.二叉树的后序遍历(非递归实现)
- v.push_back(cur->val)要记录节点,必须要把它的左右子树访问完
- 用一个prev指针记录上一次记录的节点值,
- 一个节点右不为空的情况下
- if(top->right == nullptr || top->right == prev)
- 右子树没有访问,访问右子树
- 右子树已经访问过了,那就访问且记录根节点
1.前K个高频单词
- 这里直接使用一个大堆的优先级队列
- 优先级队列也是可以通过迭代器区间来进行构造的
- 补充:map可以去重,仿函数less需要自己写
2.两个数组的交集
- 需要先排序,然后用迭代器或指针或下标进行操作
-
unique(v.begin(),v.end())返回的是去掉重复元素后的最后一个迭代器
-
排序之后用才能用unique进行去重,它需要配合erase使用