算法归类

做题步骤


  1. 确定题型
  2. 搭框架
  3. 处理细节
  4. 思考边界测试条件

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 救生艇

      • 思路:
  • 反思

    1. 要学习答案那样的代码书写方式!
    2. 哈希表最大的优点在于,键值对!另一个优点在于查找是否存在的速度比遍历快!
    3. 只有数组是有序排列的时候,对撞指针才最优
    4. 注意for each内不含索引!想要索引和对应的值,换成for(i=0;i<n;i++)
    5. 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

  • 反思

    1. 非定长也可能用滑动窗口!
    2. 第3 题中:
      1. 外层循环就是左指针!
      2. 当不知道right初值的时候,先不着急写
      3. 如果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
  • 思路
posted @ 2021-03-10 23:27  wangenhui123  阅读(61)  评论(0编辑  收藏  举报