高级进阶班1——补充(利用平凡解优化流程、通过记录结构找到可能性划分的边界情况、动态规划填表的斜率优化技巧、上中位数结构)

目录

【案例1】

【题目描述】

【思路解析】

【代码实现】

【案例2】

【题目描述】 

【题目描述】

【代码实现】

 【案例3】

【题目描述】

【思路解析】

【代码实现】

【案例4】

【题目描述】


【案例1】

【题目描述】

【思路解析】

先通过遍历数组得到整个数组的最小值和最大值,将【最小值,最大值】这个闭区间划分为n+1个小区间,然后整个数组的n个数字一定会分布在这n+1个小区间中,可能某一个区间会含有多个数,但是这些数中的相邻差值一定小于一个区间的长度,然后因为是n+1个小区间,就一定会有个别区间中没有数字,这些空区间左右的两边相邻数字差一定会大于一个区间的长度。(即这n+1个小区间,因为有空区间,所以给出了一个平凡解(区间长度),所以我们不需要再考虑一定小于平凡解的解,所以我们不必求解相同区间的相邻数字的解)。我们只用记录每个区间的最小值和最大值,然后在不同区间中求解。

【代码实现】

/**
 * @ProjectName: study3
 * @FileName: Ex1
 * @author:HWJ
 * @Data: 2023/9/16 15:57
 * 利用平凡解优化的技巧
 */
public class Ex1 {
    public static void main(String[] args) {

    }

    public static int getMaxDeviation(int[] arr){
        if (arr.length < 2) {
            return -1; // 只有一个数字的数组,无法得到两个相邻数的差
        }
        int max = Integer.MIN_VALUE;
        int min = Integer.MAX_VALUE;
        int len = arr.length;
        for (int i = 0; i < len; i++) {
            max = Math.max(max, arr[i]);
            min = Math.min(min, arr[i]);
        }
        if (max == min){ // 满足此条件表示整个数组为常数数组。
            return 0;
        }
        boolean[] hasNum = new boolean[len + 1];
        int[] maxs = new int[len + 1];
        int[] mins = new int[len + 1];
        int index = 0;
        for (int i = 0; i < len; i++) {
            index = getIndex(len + 1, arr[i], min, max);
            maxs[index] = hasNum[index] ? Math.max(maxs[index], arr[i]) : arr[i];
            mins[index] = hasNum[index] ? Math.min(mins[index], arr[i]) : arr[i];
            hasNum[index] = true;
        }
        int lastMax = maxs[0];
        int res = Integer.MIN_VALUE;
        for (int i = 1; i < len + 1; i++) {
            if(hasNum[i]){
                res = Math.max(mins[i] - lastMax, res);
                lastMax = maxs[i];
            }
        }
        return res;
    }

    public static int getIndex(int len, int num, int min, int max){
        return (int) (num - min) * len / (max - min);
    }
}

【案例2】

【题目描述】 

 给出n个数字a1,……an,问如何将这个数组划分为多个部分,使得这个划分中异或和等于0的部分尽可能多。问最多是多少。

【题目描述】

对于任何一个i位置上的数字,只有两种可能性,(1)它在最优化分情况下能使从k位置到i位置的异或和等于0 ,(2)它在最优划分情况下不能使某一个部分的异或和等于0。所以我们需要解决如果i位置能使最优划分情况下从k位置到i位置的异或和等于0,我们怎么找到这个最近的k位置。我们可以在遍历时记录从0-i位置的异或和,异或和为m,则上一次达到m的位置是k-1。利用这个记录结构我们可以找到那些部分能够使异或和为0,然后再满足不重复的条件下,得到最优划分情况。

【代码实现】

import java.util.HashMap;

/**
 * @ProjectName: study3
 * @FileName: Ex2
 * @author:HWJ
 * @Data: 2023/9/16 16:31
 */
public class Ex2 {
    public static void main(String[] args) {
        int[] arr= {3,2,1,4,0,4,0,3,2,1};
        System.out.println(getBestDivision(arr));
    }

    public static int getBestDivision(int[] arr){
        int[] division = new int[arr.length];
        HashMap map = new HashMap<>();
        map.put(0, -1); // 初始化记录表
        int xor = 0;
        for (int i = 0; i < arr.length; i++) {
            xor ^= arr[i];
            if (map.containsKey(xor)){
                int pre = map.get(xor);
                division[i] = pre == -1 ? 1 : Math.max(division[pre] + 1, division[i - 1]);
            }
            map.put(xor, i);
        }
        return division[arr.length - 1];
    }
}

 

 【案例3】

【题目描述】

【思路解析】

这道题可以看作使用普通币完成a面值有x种方法,纪念币完成m-a面值有y种方法。然后对于这样使用普通币和纪念币完成m面值的方法为 x*y。所以我们使用两个动态规划分别得到普通币完成0……m面值的方法数,纪念币完成0……m面值的方法数。

对于普通币的动态规划可以进行斜率优化。

1 0 0 1 0
1
1

对于上面的表格可以做是普通币动态规划需要填充的表格,对于上面表格dp[i, j]表示使用0……i种,完成 j 面值的方法数。假设有三种货币分别为3,2,1,需要完成的面值为4。第一列根据定义表示为,使用 i种货币完成0面值的方法数,即不使用币,均为1。第一行表示为使用3这个货币,完成 j面值的方法数,然后第二行表示为使用 2和3这两个货币,完成 j面值的方法数,对于这一行任一j位置,它依赖与dp[i-1][j]  dp[i-1][j - 3]   dp[i-1][j - 6].......对于j - 3依赖dp[i-1][j - 3]   dp[i-1][j - 6].......所以我们对于任一j位置可以优化为dp[i][j] =  dp[i-1][j ] + dp[i][j - 3] .

【代码实现】

/**
 * @ProjectName: study3
 * @FileName: Ex3
 * @author:HWJ
 * @Data: 2023/9/16 17:09
 */
public class Ex3 {
    public static void main(String[] args) {
        int[] arr1 = {2,3,4};
        int[] arr2 = {2,3,1};
        System.out.println(dpWays(arr1, arr2, 8));
    }

    public static int dpWays(int[] arr1, int[] arr2, int m){
        int[][] dp1 = new int[arr1.length][m + 1];
        int[][] dp2 = new int[arr2.length][m + 1];
        for (int i = 0; i < arr1.length; i++) {
            dp1[i][0] = 1;
        }
        for (int i = arr1[0]; i < m + 1; i += arr1[0]) {
            dp1[0][i] = 1;
        }
        for (int i = 1; i < arr1.length; i++) {
            for (int j = 1; j < m + 1; j++) {
                dp1[i][j] = dp1[i - 1][j] + ((j - arr1[i]) >= 0 ? dp1[i][j - arr1[i]] : 0);
            }
        }

        for (int i = 0; i < arr2.length; i++) {
            dp2[i][0] = 1;
        }
        dp2[0][arr2[0]] = 1;
        for (int i = 1; i < arr2.length; i++) {
            for (int j = 1; j < m + 1; j++) {
                dp2[i][j] = dp2[i - 1][j] + ((j - arr2[i]) >= 0 ? dp2[i - 1][j - arr2[i]] : 0);
            }
        }
        int ans = 0;
        for (int i = 0; i < m + 1; i++) {
            ans += dp1[arr1.length - 1][i] * dp2[arr2.length - 1][m - i];
        }
        return ans;
    }
}

【案例4】

【题目描述】

高级进阶班1——补充(利用平凡解优化流程、通过记录结构找到可能性划分的边界情况、动态规划填表的斜率优化技巧、上中位数结构)_第1张图片

你可能感兴趣的:(算法,数据结构)