算法归类
做题步骤
- 确定题型
- 搭框架
- 处理细节
- 思考边界测试条件
1、双指针
-
题眼:
升/降序
数组
两数
-
例题
-
lc 1 两数之和
-
思路:第一想法是双指针,但是数组是无序的;再想哈希表,但是也是和两数相关的,一般要遍历的话,外层计数器i 即当成左边那个指针。
-
class Solution{ public int[] twoSum(int[] nums,int target){ Map<Integer,Integer> hashtable = new HashMap<Integer,Integer>(); for(int i=0;i<nums.length;i++){ if(hashtable.containsKey(target-nums[i])){ return new int[]{hashtable.get(target-nums[i]),i}; //【要点1】Map自带get方法,键值对中,键是唯一的get(key)===>value //【要点2】Map自带containsKey(key)方法,返回Boolean类型 //【要点2.1】后面用过Set之后发现,Set自带contains()方法 //【要点3】for( Map.Entry<> xxx : hashxxx.entrySet() ) // hasxxx.entrySet() 里面才是getKey()、getValue()【用于包含键值对的for each遍历】 }else{ hashtable.put(nums[i],i); //【要点4】因为从键得到值,所以要想要得到下标,要这样构建哈希表 } } return new int[0];//【要点5】一定不要忘了,函数最后要有个返回值,这是函数的产出,就算随便写一个也行! } }
-
-
lc 141 环形链表
-
思路:快慢指针判断环形链表,只要是环形,我一定能反追上
-
public class Solution { public boolean hasCycle(ListNode head) { if (head == null || head.next == null) { //aaa return false; //答案经常会这样写,因为测试用例有不少边界条件,直接先排除 } ListNode slow = head; ListNode fast = head.next; // while (slow != fast) { //由于这个判断条件,fast要先行一步; //由于fast要先行一步,aaa处要多一个判断 if (fast == null || fast.next == null) { return false; } slow = slow.next; fast = fast.next.next; } return true; } }
-
-
881 救生艇
- 思路:
-
-
反思
- 要学习答案那样的代码书写方式!
- 哈希表最大的优点在于,键值对!另一个优点在于查找是否存在的速度比遍历快!
- 只有数组是有序排列的时候,对撞指针才最优
- 注意for each内不含索引!想要索引和对应的值,换成for(i=0;i<n;i++)
- int[] num .length 数组里面是属性,毕竟不是对象 // String a.length( )字符串里面是方法,毕竟人家是对象
2、二分查找
-
题眼:
logN
升/降序
峰值
-
例题
-
lc 704 二分查找
-
思路:基本的二分查找,套用即可!
-
class Solution { public int search(int[] nums, int target) { if(nums == null || nums.length == 0){ return -1; } int mid,left = 0; int right = nums.length -1; while(left <= right){ mid = left + (right - left) / 2; //【要点1】这种一直要求的中间变量要放在while循环里,否则超时 if(nums[mid] == target){ //【要点2】为防止溢出 mid 这样求! return mid; }else if(nums[mid] < target){ left = mid +1; }else right = mid -1; } return -1; } }
-
-
35
-
162
-
74
-
-
反思:
3、滑动窗口
-
题眼:
固定长度子串
数组
-
例题:
-
lc 209 长度最小的子数组
-
class Solution { public int minSubArrayLen(int s, int[] nums) { int n = nums.length; //【要点1】排除边界:if(nums == null || nums.length == 0) if (n == 0) { return 0; } int ans = Integer.MAX_VALUE; //【要点2】这里取int最大值,是为看窗口滑到最后还没有找到>target的情况 int start = 0, end = 0; int sum = 0; while (end < n) { // sum += nums[end]; while (sum >= s) { //【要点3】双层while,内部是为了找在满足的情况下是否还有更好的;my error ans = Math.min(ans, end - start + 1); sum -= nums[start]; start++; } end++; } return ans == Integer.MAX_VALUE ? 0 : ans; } }
-
-
1456
- 思路:滑动窗口、打擂台、哈希表--->哈希集合HashSet [a,e,i,o,u],比=='a' || =='b'.......快的多、暴力算法
-
3
-
-
反思
- 非定长也可能用滑动窗口!
- 第3 题中:
- 外层循环就是左指针!
- 当不知道right初值的时候,先不着急写
- 如果right指针实时移动的话,可能会在边界不符合的条件下,使得right多1【一个解决方法是,始终让right在要判断元素的左侧,另一个方法是后期计算窗口大小的时候-1(但是测试用例里有null,会报错)】
4、递归
- 例题
- 509
- 206
- 344
- 思路
5、分治法
- 例题
- 209
- 1456
- 思路
6、回溯法
-
例题
- 思路
7、分治法
- 例题
- 209
- 1456
- 思路
8、深度优先搜索DFS
-
例题
- 思路
9、广度优先搜索BFS
-
例题
- 思路
10、并查集
-
例题
- 思路
11、贪心算法
-
例题
- 思路
12、记忆化搜索
-
例题
- 思路
13、动态规划DP
- 例题
- 509
- 62
- 思路