a # 认识复杂度,对数器,二分法与异或 程序=算法+数据结构
评估算法的优劣
- 时间复杂度(流程决定)
- 额外空间复杂度(流程决定)
- 常数项时间(实现细节决定) 最细节的,一般省略
常数时间的操作
非常数时间的操作
如查找链表
时间复杂度
常数时间的操作次数的最高阶量级
额外空间复杂度
最优解
对数器
二分法
位运算比除运算快 同理
局部最小(无序情况下 使用二分)
只要可以构建出一种可以排掉一边的逻辑,就可以二分法
认识异或运算
java中进制转换
int a =2;
Integer.toString(a,2) //将a转为2进制
题目
- 不用额外变量交换两个变量的值
- 数组中有一个数出现了奇数次, 其他的出现了偶数次,把他找出来 (使用异或)
- 把int类型的数 提取出最右侧的1来
链表结构,栈,队列,递归行为,哈希表和有序表
栈 队列
- 双向链表实现栈 队列
- 数组实现 队列是实现:循环数组
- 主栈弹出 min栈也跟着弹出
-
题一 一个栈导入另一个栈就ok了
-
题二 把Data队列放入help,最后一个值返回用户,然后把help再放入Data中,如此循环往复
递归
- 对于某一类递归行为,时间复杂度可以直接写出来
子问题的规模是一致的,这个子问题调用了a次 O(Nd)是子问题中的规模
确定复杂度公式 直接记!!! master公式
哈希表
HasMap的特点
- hasMap中(包装类,基础类型)按值传递 既按值比较,不比较内存
- 非基础类型按引用传递
有序表
TreeMap 接口时间复杂度 O(logN)
归并排序
- 递归版
- 时间复杂度:T(N)=2T(N/2)+O(N) ===>O(NlogN)
- 非递归版
时间复杂度
选择 冒泡 插入排序浪费了比较行为(前一次的比较不会影响后续的比较行为 ) 所以是O(N^2)
题目
- 如果每个数都向后找,则时间复杂度为O(N的平方)
- 所以用归并排序优化
- 左边比它小,等价于右边比他大
快速排序
partition 小于----大于
荷兰国旗问题 小于---等于----大于
快排1.0 (partition) 复杂度 o(N2)
快排2.0 (荷兰国旗问题) o(N2)
快排 3.0 每次随机选一个数,放到最右侧进行partition
- 每次partition后训练,左右两边的数的个数越均衡,效果越好
在随机行为下 最差情况是概率时间 综合期望是 O(N*logn)
堆
使用数组表示堆,并求其节点
大根堆
构建大根堆
- 先放入末尾,之后再和其父亲节点比大小,大于父节点就交换 代价:O(logn)
- 取出堆中最大值,并且保存堆的特性
小根堆
同理
堆排序
- 额外空间复杂度o(1) 时间复杂度O(N*logN)
建堆的复杂度
heapInsert和heapify
heapInsert和父节点比 heapify和子节点比
系统通过的堆vs手写的堆
- **答:选择大小为K的小根堆进行堆排序,弹出一个进入一个 **
- 复杂度O(n*logK)
比较器
自定义排序
特殊标准
手动写堆用来,用来满足一下需求
trie 桶排序 排序总结
前缀树
- 解决前缀查询相关的问题
- 有路就走,没路就新建 比如加入gab,整条路都会是新的
前缀树的代码实现
- 节点数据结构
- 插入
- 查找带前缀的字符串的个数
- 删除字符串节点
- 方法二,使用hash表
不基于比较的排序 桶排序(一种思想的统称)
- 计数排序
- 基数排序
前提:非负,十进制 O(N)
基数排序代码实现
O(N)因为样本有规定量不大 实际上是O(Nlog已10为底的最大值的对数)
Nlog已10为底的最大值的对数=====最大数有几位
- 不再用桶来逐个放入, 而是直接算出桶里面应该有多少个元素, 这样就直接知道排序后下标的位置了.也就不需要桶了.
排序算法的稳定性
- 算法面对相等时的态度决定他是否稳定
稳定性的用途
链表相关面试题
快慢指针
重点即中间的点,偶数有两个中点
方法二
回文 adcda 栈
使用快慢指针优化
不使用额外空间
partition
方法一 荷兰国旗
方法二 使用6个指针
常见题
常用方法
题目中的链表结构 解决方法: hash表
**使用map存储原节点和被复制节点之后,拿出一对节点进行next和rand的复制,之后循环将所以节点全部复制完成。
特殊方法
这种方法代替了hash表
之后把大链表上把新节点分离出来
常见题
链表结构
如何判断链表是否有环,并且返回第一个入环节点
- 方法一 直接使用set集合把遍历的点放入之后比对。
- 方法二 快慢指针
第一步:f走两步 s走一步 当s/f相遇的时候,f回到原点,s不动,之后f和s一次都走一步,再次相遇时,就是入环节点。
判断无环链表相交点
方法一 set集合 方法二 如果两个链表相交,则结尾一定为同一个点,表1从头节点到尾节点如果为100步 表二从头到尾长度如果为80 则表1先走20步之后两个表一起走并且不停的比对,第一个相同的点就是相交点
题目剩余的情况
- 两个链表都有环
- 相交后入环(loop1==loop2) 找第一个相交点:先得出入环点相同,之后去掉入环点之后的节点 按照判断无环链表相交点的方法求
- 相交但入环的点不是一个
情况1和情况三(loop1!=loop2)
情况1:链表遍历之后loop1和再次遇到自己缺没有遇到loop2
情况3:遍历过程中再次遇到loop1自己之前遇到loop2
题目主方法
面试题
答:如果想删掉一个节点必须要头节点
二叉树
子树
遍历
递归序
非递归遍历
先序
后序
一个栈搞定
peek()函数返回栈顶的元素,但不弹出该栈顶元素。 h代表上次打印的节点,用来判断左右子树是否处理
中序
大方向是先左 后头 再右
按层遍历
题目:判断二叉树哪一层节点数量最大
使用map
想要发现每一层的开始与结束
不使用map
并不关心,具体哪一层节点最多
二叉树的序列化和反序列化
到时候根据序列进行还原即可
按层序列化
反序列化
树的打印
先右再头再左
代码
题目
后继节点:简单来讲就是在中序遍历中某节点的下一个节点。
整棵树最右的节点不会有后继
最简单解法(复杂度高) o(n)
向上早到头节点,之后中序遍历,再遍历中序序列找到要找节点的后继
低代价方法 o(k)
- 如果一个节点有右孩子,右子树中最左的节点为其后继
- 如果一个节点没用右孩子则
前驱:中序序列的序列的前一个节点
题目
** 二叉树递归套路 *********
题目
思想
需要的信息:左右树的高度,是否平衡?