一、遍历时循环变量的设计
1.双指针
从两头开始的双指针,start++;end--;
2.滑动窗口
窗口等于[start,i]
i是当前遍历到的索引
start这是窗口的起始位置
滑动窗口最主要的是想明白 什么条件下跳转 start
例如寻找符合条件的最大子数组等问题。
经典的题目非常多 121. 买卖股票的最佳时机
3. 无重复字符的最长子串 340. 至多包含 K 个不同字符的最长子串
3.贪心算法
3.1 从最优的一种情况开始 或者从0开始
例如 找面积最大的区域从两头遍历 #11 盛最多水的容器
不确定时就从0开始
3.2.假定当前遍历到的位置总是满足条件的最优解,并基于当前的最优解,做出最优选择
例如 605 种花问题
3.3 .持续这样做直到进入结束状态 ,有时候判断是否到结束状态也是很需要技巧
二、数据存储结构的优化
1. 使用MAP建立索引,用来保存已经遍历的value的状态
例如value上一次出现的位置或者value出现的次数等。
注意value需要是可穷举的有限个。
2. value反向索引数组 value[]
通常我们是按照index遍历数组,但是有时候如果value是可以穷举的那么也可以遍历value,通常需要三步
1.先建立长度为value最大可能取值个数的value[],数组的默认值填充一个默认值(最好是-1)
2.通过O(n)操作遍历原数组,建立value到索引的反向索引数组
value[]的索引index=原数组的value
value[index]=原始的index,如果不存在则标记为-1
索引反转是一种特殊的数据结构,不能算是一个算法,通常用来辅助其他算法,降低时间复杂度的,例如
LCP 40. 心算挑战 从大数开始遍历避免数组排序
345. 反转字符串中的元音字母 穷举字母避免使用map或set
这种问题的难度是如何穷举Value,有时候题目会明确指定 例如英文字母(26个),英文字符(128个),或者直接告知value的范围。
但是有时候则需要根据业务规则想明白,这种题目一般比较难。 例如
41. 缺失的第一个正数 如果要使用O(N)的时间复杂度 做到,则必须想到分析N的取值范围,索引反转,并且使用原数组保存反转索引的数组 。
3.中间计算结果的复用
3.1 典型的例子是前缀和
在遍历过程中已经结算产出的结果,可以作为下一步计算的依据,这种做法会让问题变得非常简单。
4.db数组:数组遍历型动态规划
如果结果的状态可以通过遍历数组的穷举出来,则可以动态规划完成对中间计算结果的复用。
其主要操作步骤就两步,根据业务的规则
4.1.先尝试穷举i=0,1,2等初始状态的计算结果,
4.2. 再归纳由当前计算结果推到下一步计算结果的计算公式(动态方程)
4.3 建立新数组dp数组用来保存遍历过程中每一步计算结果。这个新数组就是所谓动态规划数组。
例如 198. 打家劫舍