左神高阶提升班5(贪心尝试、范围上的尝试模型

目录

【案例1 贪心尝试】

【题目描述】

【思路解析】

【代码实现】

【案例2  范围上的尝试模型】

【题目描述】

【思路解析】

【代码实现】

【案例3  范围上的尝试模型】

【题目描述】

【思路解析】

【代码实现】

【案例4  从左至右上尝试的模型 + 范围上的尝试模型】

【题目描述】

【思路解析】

【代码实现】

【案例5 范围上的尝试模型】

【题目描述】 

【思路解析】

【代码实现】


大家觉得写得可以的话,可以加入QQ群907575059一起讨论算法知识.

【案例1 贪心尝试】

【题目描述】

【思路解析】

先将整个数组排序,如果最后一个位置的值大于limit返回Integer.MAX_VALUE,表示不可能过岸。

arr[arr.length - 1] <= limit / 2如果满足这个条件,任意两个人都可以配对上一个船
arr[0] > limit / 2 如果满足这个条件,只能一个人上一个穿

否则找到小于等于limit/2最右的位置left,然后使用两个指针,p从left往0遍历,q从left+1往arr.lenth遍历。

(1)如果 p + q <= limit,此时q++ (这里q++时,统计q遍历的长度),直到p+q>limit。此时p左边的对应长度全部满足对应的p + q < limit。如果p左边长度不足,就将所有p的用来解决q。

(2)如果p+q > limit,p--。

遍历完成后,右边剩下的每个人单独安排一个船,左边剩下的安排(leftNum + 1)/2;解决多少个q就安排多少个船。

【代码实现】

package AdvancedPromotion5;

import java.util.Arrays;

/**
 * @ProjectName: study3
 * @FileName: Ex1
 * @author:HWJ
 * @Data: 2023/9/24 16:18
 */
public class Ex1 {
    public static void main(String[] args) {
        int[] arr = {1,2,2,3,4,4,5,5,5,6,6,6,6,7,7,7,8,8,8,9,9,9,11,10,11,12};
        System.out.println(need(arr, 13));
    }

    public static int need(int[] arr, int limit) {
        Arrays.sort(arr);
        if (arr[arr.length - 1] > limit) {
            return Integer.MAX_VALUE;
        }

        if (arr[arr.length - 1] <= limit / 2) { // 如果满足这个条件,任意两个人都可以配对上一个船
            return (arr.length + 1) / 2;
        }
        if (arr[0] > limit / 2) {  // 如果满足这个条件,只能一个人上一个穿
            return arr.length;
        }

        int left = -1;
        for (int i = arr.length - 1; i >= 0; i--) {
            if (arr[i] <= limit / 2) {
                left = i;
                break;
            }
        }

        int p = left;
        int q = left + 1;
        int unSolved = 0;
        while (p >= 0) {
            int solve = 0;
            while (q < arr.length && arr[p] + arr[q] <= limit) {
                solve++;
                q++;
            }
            if (solve > 0) {
                p = Math.max(p - solve, -1); // 如果能解决完,就全部解决
                // 不能就直接赋值-1,退出循环。
            } else {
                unSolved++;
                p--;
                // 我们只用记录左边没有解决的数量,就可以通过左边总数得到左边已经解决的数量
                // 左边解决的数量,又等于右边解决的数量,通过这个又可以得到右边没有解决的数量。这样就得到了我们所需要的所有信息
            }
        }
        int leftNum = left + 1;
        int right = arr.length - leftNum;
        return right + (unSolved + 1) / 2;
    }
}

【案例2  范围上的尝试模型】

【题目描述】

【思路解析】

求公共子序列的做法看 案例6左神高阶进阶班4 (尼姆博弈问题、k伪进制、递归到动态规划、优先级结合的递归套路、子串的递归套路,子序列的递归套路,动态规划的压缩技巧)_Studying~的博客-CSDN博客

第一种做法,字符串str和它的逆序unStr求最长公共子序列则是他们的最长回文子序列。

第二种做法,给出一个定义dp[i][j]表示str【i 。。。j】上的最长回文子序列长度。

则最长回文子序列可能性包括:

(1)包含i位置,包含j位置,只有str[i] == str[j]

(2)包含i位置,不包含j位置

(3)不包含i位置,包含j位置

(4)不包含i位置,不包含j位置。

【代码实现】

package AdvancedPromotion5;


/**
 * @ProjectName: study3
 * @FileName: Ex2
 * @author:HWJ
 * @Data: 2023/9/24 16:59
 */
public class Ex2 {
    public static void main(String[] args) {
        String str = "123akmk321";
        System.out.println(getMax(str));
    }

    public static int getMax(String s){
        char[] str = s.toCharArray();
        int[][] map = new int[str.length][str.length];

        for (int i = 0; i < str.length; i++) { // 填充i == j 和 j == i + 1的情况,这个是很好的判断,不用考虑可能性
            map[i][i] = 1;
            if (i < str.length - 1){
                map[i][i + 1] = str[i] ==  str[i + 1] ? 2 : 1;
            }
        }
        for (int i = str.length - 3; i >= 0; i--) {
            for (int j = i + 2; j < str.length; j++) {
                int p1 = map[i][j - 1];
                int p2 = map[i + 1][j];
                int p3 = map[i + 1][j - 1] + (str[i] == str[j] ? 2 : 0);
                map[i][j] = Math.max(p1, Math.max(p2, p3));
            }
        }
        return map[0][str.length - 1];
    }
}

【案例3  范围上的尝试模型】

【题目描述】

【思路解析】

构造结果dp[i][j]表示把str[i.....j]变为回文串至少需要多少添加字符。

(1)str[i] != str[j],此时分为两种策略,先搞定str[i......j-1]让其变为回文串,然后再将次回文串的左侧填加一个str[j]则整体是一个回文串。或者先搞定str[i +1......j]让其变为回文串,然后再将次回文串的右侧填加一个str[i]则整体是一个回文串。

(2)str[i] == str[j],此时只用将str[i+1 ...... j-1]变为回文串,整体就是回文串。

最后三种可能性求最小值,则得到我们需要的答案。通过动态规划填完表后,我们通过表逆推得到返回的答案。

【代码实现】

package AdvancedPromotion5;

/**
 * @ProjectName: study3
 * @FileName: Ex3
 * @author:HWJ
 * @Data: 2023/9/24 17:10
 */
public class Ex3 {
    public static void main(String[] args) {
        String s = "123afga1321";
        System.out.println(record(s));
    }

    public static String record(String s) {
        int[][] map = recordMap(s);
        String ans = recordStr(map, s.toCharArray());
        return ans;
    }

    public static int[][] recordMap(String s) {
        char[] str = s.toCharArray();
        int len = str.length;
        int[][] map = new int[len][len];
        for (int i = 0; i < len; i++) {
            map[i][i] = 0;
            if (i < len - 1) {
                map[i][i + 1] = (str[i] == str[i + 1] ? 0 : 1);
            }
        }
        for (int i = len - 3; i >= 0; i--) {
            for (int j = i + 2; j < len; j++) {
                int p1 = map[i + 1][j] + 1;
                int p2 = map[i][j - 1] + 1;
                map[i][j] = Math.min(p1, p2);
                if (str[i] == str[j]) {
                    map[i][j] = Math.min(map[i][j], map[i + 1][j - 1]);
                }
            }
        }
        return map;
    }

    public static String recordStr(int[][] map, char[] str) {
        int len = map.length;
        int need = map[0][len - 1];
        int p = 0;
        int q = len - 1;
        char[] ans = new char[len + need];
        int i = 0;
        int j = ans.length - 1;
        while (p <= q) {
            if (p == q) {
                ans[i] = str[p];
                break;
            }
            if (str[p] == str[q]) {
                int p1 = map[p + 1][q - 1];
                int p2 = map[p + 1][q];
                if (map[p][q] == p1) {
                    ans[i++] = str[p++];
                    ans[j--] = str[q--];
                } else if (map[p][q] == p2 + 1) {
                    ans[i++] = str[p];
                    ans[j--] = str[p++];
                } else {
                    ans[i++] = str[q];
                    ans[j--] = str[q--];
                }
            } else {
                int p1 = map[p + 1][q];
                if (map[p][q] == p1 + 1) {
                    ans[i++] = str[p];
                    ans[j--] = str[p++];
                } else {
                    ans[i++] = str[q];
                    ans[j--] = str[q--];
                }
            }
        }
        return String.valueOf(ans);
    }
}

【案例4  从左至右上尝试的模型 + 范围上的尝试模型】

【题目描述】

【思路解析】

因为我们要将其全部切成回文子串的最小切割数,则可以从左至右遍历每种可能性,遍历可能性时判断当前切割是否合理,如果当前切割保证当前切下来的是合理回文子串,即继续往下切。这种遍历下时间复杂度O(N^2),又因为每次遍历都要进行一次判断过程,判断时间复杂度O(N),所以总体时间复杂度为O(N^3)。这时时间复杂度过高,我们需要通过范围上的模型来对判断过程加速。

统计一个表,map[i][j]表示str[i....j]是不是回文子串,回文子串一定要满足str[i] == str[j],并且str[i + 1][j - 1]也是回文子串。

【代码实现】

package AdvancedPromotion5;

/**
 * @ProjectName: study3
 * @FileName: Ex4
 * @author:HWJ
 * @Data: 2023/9/25 8:32
 */
public class Ex4 {
    public static void main(String[] args) {
        String str = "ABA";
        boolean[][] map = judge(str);
        System.out.println(getMin(str.toCharArray(), 0, map));
    }

    public static int getMin(char[] str, int index, boolean[][] map){
        if (index == str.length){
            return -1;
        }
        int res = Integer.MAX_VALUE;
        for (int i = index; i < str.length; i++) {
            if (map[index][i]){
                res = Math.min(res, 1 + getMin(str, i + 1, map));
            }
        }
        return res;

    }

    public static boolean[][] judge(String s){
        boolean[][] map = new boolean[s.length()][s.length()];
        char[] str = s.toCharArray();
        for (int k = 0; k < str.length; k++) {
            map[k][k] = true;
            if (k < str.length - 1){
                map[k][k + 1] = str[k] == str[k + 1];
            }
        }
        for (int k = str.length - 3; k >= 0 ; k--) {
            for (int l = k + 2; l < str.length; l++) {
                if (str[k] == str[l]){
                    map[k][l] = map[k + 1][l - 1];
                }else {
                    map[k][l] = false;
                }
            }
        }
        return map;
    }
}

【案例5 范围上的尝试模型】

【题目描述】 

【思路解析】

构造一个二维表,map[i][j]表示str[i .....j]有多少个回文子序列。

则回文子序列分为以下可能性:

(1)包含i位置,包含j位置。

(2)包含i位置,不包含j位置。

(3)不包含i位置,包含j位置。

(4)不包含i位置,不包含j位置。

map[i + 1][j] 表示不包含i位置的所有回文子序列个数,可能包含j位置,也可能不包含j位置,代表(3)(4)可能性。j

map[i][j - 1] 表示不包含j位置的所有回文子序列个数,可能包含i位置,也可能不包含i位置,代表(2)(4)可能性。

map[i+1][j-1]表示不包含j位置并且不包含j位置的所有回文子序列个数,代表(4)可能性。

(1)可能性只有在str[i] == str[j]时才有这个可能性,数值等于map[i+1][j-1] + 1.因为如果如果除去这两个是回文数,加上任然是回文数,并且多一个只有这两个序列的情况。

【代码实现】

package AdvancedPromotion5;

/**
 * @ProjectName: study3
 * @FileName: Ex5
 * @author:HWJ
 * @Data: 2023/9/25 9:05
 */
public class Ex5 {
    public static void main(String[] args) {
        String str= "ABA";
        System.out.println(getNum(str));
    }

    public static int getNum(String s){
        char[] str = s.toCharArray();
        int len = str.length;
        int[][] map = new int[len][len];
        for (int i = 0; i < len; i++) {
            map[i][i] = 1;
            if (i < len - 1){
                map[i][i + 1] = (str[i] == str[i + 1] ? 3 : 2);
            }
        }
        for (int i = len - 3; i >= 0; i--) {
            for (int j = i + 2; j < len; j++) {
                map[i][j] = map[i + 1][j] + map[i][j - 1] - map[i + 1][j - 1];
                if (str[i] == str[j]){
                    map[i][j] += (map[i + 1][j - 1] + 1);
                }
            }
        }
        return map[0][len - 1];
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_73936404/article/details/133232169