查找大小为M的最新分组

76 阅读2分钟

题目

类动态规划

public class Main {
    public static void main(String[] args) {

        Main main = new Main();
        int [] nums = new int[] {3, 5, 1, 2, 4};
        main.findLatestStep(nums, 1);
    }

    public int findLatestStep(int[] arr, int m) {

        // 考虑每个步骤二进制字符串新增的1对之前结果的影响

        // dp[arr[i] - 1]记录了二进制字符串中以arr[i] - 1作为起始, 或者以arr[i] - 1为结尾的连续1的长度
        int dp [] = new int[arr.length];

        // 布尔数组表示二进制字符串中哪些位置为1
        boolean [] isOne = new boolean[arr.length];

        // 记录现存的长度可能
        int [] count = new int[arr.length + 1];

        int lastStep = -1;
        for(int i = 0; i < arr.length; i ++) {
            // 此次添加元素出现的长度
            int thisLength = 1;
            // index代表在二进制字符串中的索引位置
            int index = arr[i] - 1;
            isOne[index] = Boolean.TRUE;
            dp[index] = 1;
            // 该位置能否成为连续1的开头
            if (index + 1 < arr.length && isOne[index + 1]) {
                // 减去count中的次数
                count[dp[index + 1]] --;
                int endIndex = index + 1 + dp[index + 1] - 1;
                // 起始位置变成长度+1
                dp[index] = dp[index + 1] + 1;

                // 终止位置和起始位置长度一致
                dp[endIndex] = dp[index];

                thisLength = dp[index];
            }

            // 判断该位置能否成为连续1的结尾
            if (index - 1 >= 0 && isOne[index - 1]) {
                // 减去count中的次数
                count[dp[index - 1]] --;

                int startIndex = index - 1 - (dp[index - 1] - 1);
                // 修改起始位置的长度值
                dp[startIndex] = dp[index - 1] + dp[index];

                // 终止位置和起始位置长度一致
                dp[index + dp[index] - 1] = dp[startIndex];

                thisLength = dp[startIndex];
            }
            count[thisLength] ++;
            if (count[m] > 0) {
                lastStep = i + 1;
            }
        }

        return lastStep;
    }

}

基本思路

  1. 题目是每次将二进制中一位数字修改为1, 因此根据动态规划的思想, 考虑此次修改带来的变化, 也就是根据当前位置左边一位的结果, 和右边一位的结果, 得到此次改变的结果

  2. 利用一个dp数组, dp[i]表示以i开头或者以i结尾的连续1的长度

  3. 利用一个布尔数组, 记录索引处的元素是否为1

  4. 每次在i位置从0变1的时候, 首先判断i能否作为连续1的开头, 再判断能否作为连续1的结尾, 修改dp中首尾的值

  5. 利用count数组记录此次变化消去的长度可能和新添加的长度可能, 例如[1, 0, 1]变成[1, 1, 1]即消了两个长度1, 新增一个长度3的可能