Fork me on GitHub

算法-技巧

1.回文子串(动态规划)

  • P(i,j)=(P(i+1,j1)&&S[i]==S[j])
  • 如果 S[i+1,j-1]S[i+1,j−1] 是回文串,那么只要 S[ i ]S[i] == $S[ j ] $,就可以确定 S[i,j]S[i,j]也是回文串了。
  • 求 长度为 11 和长度为 22 的 P(i,j)P(i,j) 时不能用上边的公式,因为我们代入公式后会遇到 P[i][j]P[i][j] 中 i > j 的情况,比如求 P[1][2]P[1][2] 的话,我们需要知道 P[1+1][2-1]=P[2][1]P[1+1][2−1]=P[2][1] ,而 P[2][1]P[2][1] 代表着 S[2,1]S[2,1] 是不是回文串,显然是不对的,所以我们需要单独判断。

 2.数字技巧

  • 掌握 / 和 % 可以解决很多问题,例如数学12整数转罗马文字
  • 2200 / 1000 == 2 相除得到整数结果,余数忽略
  • 2200 % 1000 == 200 取余忽略整除结果,只取余数
  • char型数组转 int,char - ‘0’

3.数组中的数字操作

  应该想到指针! 多指针操作

4.动态规划思路

  二维数组,计算两点的路径数量总和的问题,动态方程:dp[i][j] = dp[i-1][j] + dp[i][j-1]

5.深度优先遍历

  如果需要进行上下层级之间的比较,每次处理一个节点就好,左右节点递归处理

6.回溯模板代码

  回溯不可重复

/**
     * 回溯算法不可重复 相当于每一层选择一个进行排列组合
     * in: 1 2 3
     * out: [1]
     *      [1, 2]
     *      [1, 2, 3]
     *      [1, 3]
     *      [2]
     *      [2, 3]
     *      [3]
     */
    public void backtrack(int[] nums , int index , Stack<Integer> temp){
        for(int i  = index; i < nums.length; i++){
            temp.push(nums[i]);
            backtrack(nums,i + 1 , temp);
            temp.pop();
        }
    }

  回溯可重复

/**
     * 回溯算法重复 相当于每一层都有nums.length 个选择 进行排列组合
     * in:1 2
     * out:[1, 1, 1]
     *     [1, 1, 2]
     *     [1, 2, 1]
     *     [1, 2, 2]
     *     [2, 1, 1]
     *     [2, 1, 2]
     *     [2, 2, 1]
     *     [2, 2, 2]
     *
     */
    public void backtrack_CF(int[] nums , Stack<Integer> temp){
        if(temp.size() >= 3){
            System.out.println(temp);
            return;
        }
        for(int i  = 0; i < nums.length; i++){
            temp.push(nums[i]);
            backtrack_CF(nums,temp);
            temp.pop();
        }
    }

  

7.子序问题 ==> 都可以用动态规划来解决

  最大连续子序和:dp(i)=max(dp(i-1)+array[i],array[i])

    /**
     * 推导公式 : dp(i)=max(dp(i-1)+array[i],array[i])
     */
    private int MaxCountOf(int[] array){
        //max就是上面的dp[i]
        int max = array[0];
        //因为这个dp[i]老是变,所以比如你dp[4]是8 dp[5]就变成-7了,所以需要res保存一下
        int res = array[0];
        for (int i = 1; i < array.length; i++) {
            max = Math.max(max + array[i], array[i]);
            res = Math.max(res, max);
        }
        return res;
    }

  最长递增子序:dp[i] = max(dp[i], dp[j] + 1) for j in [0, i)。

    public int lengthOfLIS(int[] nums) {
        if (nums.length == 0)
            return 0;
        int[] dp = new int[nums.length];
        int res = 0;
        Arrays.fill(dp,1);
        for (int i=0;i<nums.length;i++){
            for (int j=0;j<i;j++){
                if (nums[i]>nums[j]) dp[i] = Math.max(dp[i],dp[j]+1);
            }
            res = Math.max(res,dp[i]);
        }
        return res;
    }

  最长公共子序:

  (1) 如果S的最后一位等于T的最后一位,则最大子序列就是{s1,s2,s3...si-1}和{t1,t2,t3...tj-1}的最大子序列+1
  (2) 如果S的最后一位不等于T的最后一位,那么最大子序列就是  
      ① {s1,s2,s3..si}和 {t1,t2,t3...tj-1} 最大子序列
      ② {s1,s2,s3...si-1}和{t1,t2,t3....tj} 最大子序列
  
    public int longestCommonSubsequence(String text1, String text2) {
        char[] s1 = text1.toCharArray();
        char[] s2 = text2.toCharArray();
        int[][] dp = new int[s1.length+1][s2.length+1];
        for (int i=1;i<s1.length+1;i++){
            for (int j=1;j<s2.length+1;j++){
                if (s1[i-1] == s2[j-1]){//最后一位相同
                    dp[i][j] = dp[i-1][j-1] +1;
                }else{//最后一位不同
                    dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);
                }
            }
        }
        return dp[s1.length][s2.length];
    }

8.字母的任意组合问题

  dpi=dp(i1)+dp(i2)   

9.位运算

  X&1 是取X二进制的最低以为   

       X>>1 向右移1位

      位运算 x & (x-1)  将最低位的1置为0

  如果n是2的幂次方 则 : n & (n - 1) == 0
       大小写转换 a ^ (1<<5)  可以实现大小写转换


posted @ 2019-11-20 10:40  啊慌  阅读(222)  评论(0)    收藏  举报