归并排序, 改变有序区间(从1开始)
快速排序 {}3
堆排序 取出最大值存入数组
希尔排序 以距离值 跳跳比
桶排序
计数排序
身高
基数排序 个位数 序列 十位数 百位数
时间O(N*N)
冒泡 选择
O(N*logN)
快速
空间复杂度
O(1)
插入 选择 冒泡 堆排序 希尔排序
但是如果使用的是递归实现的,空间复杂度将不再是O(1),而是O(logN) 函数栈
OlgN-O(N)
快速
43335 快速不稳定
5115 希尔排序不稳定
快速排序:常量系数低
如果没有空间复杂度的限制,用哈希表实现
哈希表实现,时间复杂度为O(N),空间复杂度为O(N)
O(1)
先排序
从后往前拷贝,避免原有的数据被覆盖,比较和拷贝
看当前数
|
{} 1 1 0 0 2 1 1 0 {}
0区 2区
查找矩阵中的有序数
数组右上角开始
需要排序的最短子数组的长度
【1,5,4,3,2,6,7】
返回4 【5,4,3,2】
方法:从左往右记录遍历过的最大值位置,会发生一种情况,当前的元素比右边的数大,记录这种情况的最右边的位置
在从右往左,同理
最后最小和最大的位置区间就是要进行排序的区间长度。
数组中的最大差值
例如某数组排序之后为
1 2 3 4 7 8 9
最大差值来自于4和7,所以返回3
思想来自于桶排序
遍历数组
最小 最大 N区间 元素个数
N+1 为最大值
构造空桶
空桶区间 的最大差值即为最大差值
广泛性
1.1 字符串数组 查找 排序
1.2 字符串对象
需要掌握的概率
需要掌握的操作
字符串题目的常见类型
规则判断
数字运算
int 和long 类型表达整数范围有限,所以经常用字符串实现大整数
与大整数相关的加减乘除操作,需要模拟笔算的过程
与数组有关的排序有关类型
字符计数
固定长度的数组
C/C++ 字符256 java 65536
滑动窗口问题、寻找无重复字符串子串问题、
计算变位词问题
动态规划问题
搜索类型
高级算法与数据结构解决的问题
比较两棵树,T1中包含T2的子树,返回TRUE,否则返回false
方法1,遍历二叉树+判断匹配 O(N*M)
方法2:二叉树序列化+ KMP算法 O(M+N)
实际为KMP比较字符串
变形词
str1=“123” str2=”231” 返回TRUE
str1=“123” str2=”2331” 返回False
方法:使用哈希表 str1 str2 判断记录是否一致
可以借用数组
旋转词
str1=“1 2 3 4”
str1+str1=“ 1 2 3 4 1 2 3 4”
穷举了所有的旋转词
单词间逆序
一个字符串str,和一个整数i,i代表str中的位置,将str[0..i]移动到右侧,str[i+1..N-1] 移到左侧
str=”ABCDE” ,i=2. 将str调整为“DEABC”
要求,时间复杂度为O(N),额外空间复杂度为O(1)
原地调整
分为两步
1. 将str[0..i] 部分的字符逆序
A B C D E
C B A D E
C B A E D
活用局部逆序函数
strs=[“abc”, “de”];
abcde deabc 返回abcde
strs==[“b”,”ba”]
bab bba 返回bab
O(N*logN)
实质是排序
如果str1+str2
长度变化的规律,从后往前拷贝
str=() true str(()()) true
str=()) false str=()( false
str=()a() false
str=“abcd” 返回4
str=”bacb” abc 返回3
哈希表 -> 统计之前每个字符的位置
整型pre->s[i-1]结尾的情况下,无重复的长度
位置A 位置B
c
1、 栈是先进后出
栈结构的基本
1.pop
2.top 访问不弹出
3.push
4.size
双端队列
优先级队列
优先级队列为堆结构,不是线性结构
深度优先遍历DFS 和宽度优先遍历 BFS
要求:
1.pop、push 、getMin操作的时间复杂度都是O(1)
2. 设计的栈类型可以使用现成的栈结构
方法一、 StackData StackMin
1 2 1 5 4 3
压入条件是只有当前数小于等于StackMin的栈顶时,放入StackMin
弹出条件 相等StackMin
StackMin 都保存了当前的最小值 时间和空间不同
StackPush StackPop 倒入
两个重要的注意点:
1.一次性全部导入
2. StackPop 压入之前需要为空
// function: 移除栈底元素并返回
public int get(Stack stack){
int result=stack.pop();
if(stack.isEmpty()){
return result;
}else{
int last=get(stack);
stack.push(result);
return last;
}
}
// function2 reverse
/*将栈中元素逆序*/
public void reverse(Stack<Interger> stack){
if(stack.isEmpty()){
return;
}
int i=get(stack);
reverse(stack);
stack.push(i);
}
Stack help
方法:双端队列
4 3 5 4 3 3 6 7
qmax={},
1.如果qmax为空,直接把下标i放入qmax中
3 4 5 1 2
左边第一个大的数 右边第一个大的数
3-> null 3->4
4->null 4->5
5->null 5->null
1->5 1->2
2->5 2->null
5
/ \
4 2
/ \
3 1
1.该方法可以生成一棵树,而不是森林
2.生成的这一棵树是二叉树,而不是多叉树
任何一个数在单独一侧,孩子的数量都不超过一个
….A…K1…K2
A>K1 且A>K2
利用栈获取左边比他大的第一个数
同理可得右边
1.链表的分类 单链表 双链表
2.有环无环 循环链表
链表问题代码实现的关键点
1. 链表调整函数的返回值类型,根据要求往往是节点类型。
2. 思考哪些指针发生了改变,画图,查看修改的指针。
3. 边界(头节点、尾节点、空节点)
1、 如果原链表为空
2、 如果链表不为空
3、 转了一圈之后都没有发现插入的位置,此时node插入头节点的前面。
- 如果node节点的值都大于链表中的值,则直接返回head节点
- 如果node节点的值比head节点值小,则应该返回以此节点的链表
前面不可见
1->2->3->null
节点删除不正确时的影响: 节点工程依赖,或者节点结构并没有真正的删除,只是节点的值拷贝
简单做法:
1. 将链表的所有节点放入数组中,然后将数组进行快排划分
2. 把数组联系起来
最优解:
分解成3个链表,在连接起来
1 3 4 5 ->null
2->3->4->null
方法一:
k=3
栈逆序
最后一次不足K个时,单独处理
第一组的特殊 各组的连接
方法二:
收集K个元素后逆序该组
7->1->3->1
方法1.构建链表
链表1->2->3->2->1 是回文结构,返回TRUE
链表1->2->3->1 不是回文结构,返回false
方法一:时间O(n) 空间O(n)
遍历压入栈
弹出和遍历比对
方法二:时间O(n) O(N)/2
fast 每次走两步
slow
方法三:时间O(n) O(1)
找到中间节点,两边依依对比
哈希表普通做法
第一个节点重复时,返回即可,否则为空
快慢指针
有环会相遇 相遇时,快慢各走一步,再次相遇,返回
快->null 则无环
遍历两个链表的长度,长的先走,再同步走,如果相交,则一定会返回
方法:
1. 判断单链表是否有环
2. 如果node1和node2,一个为空,另一个不为空,返回空
arr : ——-mid ———m
二分搜索的重要提醒:
mid=(left+right)/2
mid=left+(right-left)/2 //更好的写法防止溢出
二分搜索
时间O(logN)
1. arr为空或者长度为0,返回-1,表示不存在
2. 如果arr 长度为1,返回0,
3. 如果arr长度大于1
1 2 3 3 3 3 4 4 4 4 4 4 4 4 4
num=3
res=-1 // 如果没有找到num=3,直接返回-1
res=2; // 下标 数组
arr[L]<=arr[R]
arr[L]>arr[M]
res=-1;
arr:
下标: arr[0]>N-1 返回-1
arr[N]<0 返回-1
arr[M]>M
arr[M]
最优解:二分搜索
1. 找到二叉树的最左节点 得到高度
2. 找到右子树的最左子孩子 找完全二叉树
10^75=10^1001011
=10^64*10^8*10^2*10^1
二叉树的结构
class Node{
int value;
Node left;
Node right;
Node(int data){
this.value=data;
}
}
先序
中序
后序
栈 ,先压入右孩子
栈, 中序 先压入左孩子,发现为空时,弹栈
非递归的后序实现
方法一:使用两个栈实现
1.申请一个栈,记为s1,然后将头节点压入S1
2. 从S1中弹出的节点记为cur,然后先把cur的左孩子压入s1中,然后把cur1的右孩子压入S1中
3. 在整个过程中,每一个从s1中弹出的节点都放在第二栈s2中。
4. 不断重复步骤2和步骤3,直到s1为空,过程停止。
5、 从s2中一次弹出节点并打印,打印的顺序就是后序遍历的顺序了。
方法二: 使用一个栈
队列:
打印二叉树
按层,连同行号打印
last:当前行的最右节点
nlast :下一行的最右节点
换行的条件为: nlast==last->next;
二叉树的序列化和反序列化
结束符!#
反序列化
生成一个数组,values={“12”,”3”,”#”,”#”}
判断一颗树是否为平衡二叉树
LH-LR 是否大于1
搜索二叉树的中序一定是从小到大的。
最后一层没有满
最优解法:
二叉树节点之间的距离
不安全黑名单100亿个黑名单URL 哈希表或数据库
布隆过滤器精确 代表一个集合
bitarray
k个哈希函数 (优秀且K个哈希函数各自独立)
每一个位置为一个bit
0:白 1: 黑
大小为m,样本数量为n,失误率为p
n=100亿
如何确定bitarray 的大小
布隆过滤器的过程
1. 失误率
2. 确定样本个数n
a=a^b;
b=a^b;
a=a^b;
方法二:
避免溢出
public static int geMax2(int a,int b){
int c=a-b;
// a的符号,as==1表示a为非负,as==0表示a为负
int as=sign(a);
// b的符号,bs==1表示b为非负,bs==0表示b为负
int cs=sign(c); // a-b 的符号
// 表示a和b是否符号不相同,不相同为1,相同为0
int difab=as^bs;
//表示a和b是否符号相同,相同为1,不相同为0
int sameab=flip(difab);
int returnA=difab*as+sameab*cs;
int returnB=flip(returnA);
return a*returnA+b*returnB;
}
n与0异或 结果为n
n与n异或结果为0
eo=0; arr=[C,B,D,A,A,B,C]
1.异或运算满足交换律
2. 结合律
异或运算可完成简单的加密和解密
概率组合
13
c13 5 c13 8
第一问: 不相邻的时候
7! 一半在A的左边
7!/2
第二问:
6!
方法一:
6!=720
甲 乙 丙 丁
甲乙看成一个人
5!+5!
乙甲丙 4!X 2=
甲在开头末尾
C3 2 X 3!
C3 2 X 3! X4
0 0 0 | 0 0 0 0 | 0 0 0
10颗糖果中间的位置为9个
所以目标转换为9个空隙中选两个插入隔板
C9 2=36种
球和桶不同
因为每个球都有3种可能
3^10 =59049
一天 1 种
C9 1 两天
三天 C9 2
2^9=512
(-> 1
) ->-1
n+1个1 和n-1个-1组成的排列
不合法的排列数=n+1
左括号数量为n,右括号数量为n,总排列数为C2n n
c2n n - C2n n+1 = 1/n+1 *C2n n
进栈(
出栈)
C2n n - C2n n+1=1/n+1*C2n n
10 5
C2n n - C2n n+1=1/n+1*C2n n
假设n个无差别的结构不同结构数为f(n)
1 1 5
f(0)=1
1/n+1*C2n n
卡特兰数
0:在第一排
1:在第二排
0 0 0 0 1 1 0 1 0 1 1 1
|
前四个人在第一排
5 6 个人在第二排
。。。
如果前缀1比0个数多的哈,说明必然会出现不合法的情况。
问题变为任意 前缀不能出现1比0多的情况,依然是卡特兰数问题
递归:
f(n)
n>2
n - i个信封
情况一: i 封 放入了n个信封中,后续为f(n-2)
情况二:第i封信没放入n个信封中,后续 为f(n-1)
f(n)=(n-1)*[f(n-1))+f(n-2)]
概率的应用
一组 二组 三组 四组
7 x 5 x 3 x 1 =105
O O O 3 个强队
O O O O O 5 个弱队
在5只弱队中选出3只与强队配对,剩下的2只自行配对。
C5 3 X A3 3=60;
从5只弱队中 3只强队和3只弱队
选出3只弱队 彼此配对的方法数
的方法数
如果方向并不都相同,则一定会相遇
每只蚂蚁方向数有2种,一共有3只蚂蚁
所以总的情况有2^3=8种
只有完全顺时针和完全逆时针这两种情况下不相遇。
所以相遇的概率为 (8-2)/8=3/4
假设这一地区共有n个家庭
假设n/2 第一胎就是男孩为,所以只有1个孩子
有n/4 的家庭先生出1女孩,再生1男孩,有2个孩子
有n/8的家庭先生2个女孩,再生1个男孩,有3个孩子
孩子的总数为:
n/2+(n/4)*2+(n/8)*3+(n/16)*4…= 2*n
每个家庭都会有一个男孩,所以2n的孩子中,男孩数为n,所以女孩数也为n.
所以比例依然为1:1
给定一个等概率随机产生1-5的随机函数,除此之外,不能使用任何额外的随机机制,请实现等概率随机产生1~7的随机函数
。
1、已经有等概率随机产生 :1 2 3 4 5
第二步:第一步-1 0 1 2 3 4 为f()
3. f()*5 0 5 10 15 20
4. f()*5+f() 1 2 3 4…24
5. 重复4,产生0~20
6. 0~20%7 可以产生3个0~6,然后+1 产生0~7的随机函数
给定一个以p概率产生0,以1-p概率产生1的随机函数f(),p是固定的值,但你并不知道是多少,除此之外也不能用任何额外的随机机制,请用f()实现等概率随机产生0和1的随机函数。
f() 产生0 p
产生 1 1-p
产生01和10序列的概率都为pX(1-p)
不断调用f,指导能够产生01或10,序列终止。
如果为01 返回0
如果为10 返回1
给定一个长度为N且没有重复元素的数组arr和一个整数M,实现函数等概率随机打印arr中的M个数。
arr 0 00 0 0 0 0 0
1 2 3 4 5…
0~N-1中得打印一个随机数
之后将打印过的数放到最后,避免重复打印,并且减小了打印的范围。
等概率随机常与最后交换。
机器吐出自然数球