双指针的类型
背向双指针
- Longest Palindromic Substring的中心线枚举算法
- 二分法中的Find K Closest Elements
相向双指针
- Reverse型(题目不多)
- Two Sum型(两位数的相关变形题)
- Partition(两位数相关变形题)
同向双指针
- 滑动窗口类 Sliding Window
- 快慢指针类 Fast & Slow Pointers
相向双指针
两根指针一头一尾,向中间靠拢直到相遇
时间复杂度O(n)
两数之和-数据结构设计
使用HashMap的做法
AddNumber-O(1)
FindTwoSum-O(n)
其中FindTwoSum函数会输入一个目标和value,需要for循环HashMap里的每个num,检查以下value-num是不是也在HashMap里,这个过程需要总共O(n*1)的时间
使用Two Pointers的做法(太慢)
AddNumber-O(n)
FindTwoSum-O(n)
其中AddNumbe可以使用Insertion Sort的方法,先将数加到数组的末尾,然后一直往前交换到它所在的位置
一边增加数一边保持数组有序?
A:Binary Search + Array Insert(支持数组的查询,不支持数组的插入)
B:Binary Search + Linked List Insert(支持插入,不支持查询)
C:Heap(支持找最大最小,不支持在O(n)时间内,把所有数从小到大输出,只能在O(nlogn)的时间内)
D:TreeMap红黑树可以做到O(n+logn),O(logn)的插入和删除,O(n)的时间从小到大把数字拿出来
三数之和(统计所有的和为0的三元组(Triples))
降维思想
需要去重,需要检查溢出
三角形个数
两边之和>第三边 a+b>c
不需要去重,如果已经大于c了,可以利用right-left求个数
四数之和
1.4数之和
在数组中求a+b+c+d=target,先for a再for b最后for c+d
2.来自4个数组的4数之和
在4个数组中,分别取4个数,使得和为target,求满足条件的四元组个数
折半查询,把a+b所有的二元组放到hash表中,然后for c+d 判断-(c+d)在不在hash表中,在有几个数
只剩一个没有判断时,其值时固定的,所以时间复杂度少乘一个n
k数之和
1.求方案总数
动态规划
2.求具体方案
用深度优先搜素
分割数组
数组严格的分为<k的部分和>=k的部分
快排Quick Sort记得比较时,不能加=,否则时间复杂度会退化为O(n^2),可以比较均匀地分割
- 为什么会有如上等号的区别?
- 目标不同,Partition Array需要严格的左半部分<k,右半部分>=k;Quick Sort/Quick Select只需要左半部分整体<=右半部分即可;如果Quick Sort/Quick Select把==pivot的严格划分到左边或者右边,会导致极端情况发生而时间复杂度很容易退化到O(n^2),如排序[1,1,1,1,1]
交替正负数
不使用额外空间——双指针算法
AAABBB:隔一个位置跳着进行交换
相关题:
Partition Array by Odd and Even
SortLetters by Case
排颜色(不能使用计数排序Counting Sort)
1.一个相当直接的方法时使用计数排序扫描2遍的算法
- 首先,迭代数组计算0,1,2出现的次数,然后依次用0,1,2出现的次数去覆盖数组。
2.能否想出一个仅用常数级额外空间复杂度且只扫描遍历一遍数组的算法?
- 设立三根指针,left,right,index,定义的规则如下:
left的左侧都是0(不含left)
right的右侧都是2(不含right)
index从左到右扫描每个数,如果碰到0就丢给left,碰到2就丢给right(此时,不需要index+1,因为要再次判定A[right]的值)。碰到1就跳过不管。
彩虹排序
1.n是颜色个数,k是颜色种类
2.时间复杂度O(nlogk)都有什么类型?
-n × logk:先降维再排序。log级别算法有哪些?- 利用数据结构:heap,红黑树。二分法,欧几里得算法(求两数最大公约数), 快速幂算法(x^k->logk),倍增算法。
- logk × n:先排序。归并排序化成树状结构,第一层两个n/2相加,第二层四个n/4相加...每一层用于归并上的耗费总时间都是总O(n),一共是logn层。
综上,利用了快排(partition)和归并(分治)
class Solution{
public:
void sortColors2(colors,k){
sort(colors,1,k,0,colors.size()-1);
}
void sort(colors,color_from,color_to,index_from,index_to){
if(color_from==color_to||index_from==index_to)
return;
color=color_from+(color_to-color_from)/2;
int left=index_from,right=index_to;
while(left<=right){
while(left<+right&&colors[left]<=color){
left++;
}
while(leftleft<+right&&colors[left]>color){
right--;
}
if(left<=right){
swap(colors[left],colors[right]);
left++;
right--;
}
sort(colors,color_from,color,index_from,right);
sort(colors,color+1,color_to,left,index_to);
}
移动零
1.如果不需要维持原来数组中元素的相对顺序,最优算法是什么?
- 相向双指针 partition:4次修改
2.如果需要维持原来数组的相对顺序,最优算法是什么?
- 同向双指针(slow,fast):5次更改