题目
类动态规划
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, 因此根据动态规划的思想, 考虑此次修改带来的变化, 也就是根据当前位置左边一位的结果, 和右边一位的结果, 得到此次改变的结果
-
利用一个dp数组, dp[i]表示以i开头或者以i结尾的连续1的长度
-
利用一个布尔数组, 记录索引处的元素是否为1
-
每次在i位置从0变1的时候, 首先判断i能否作为连续1的开头, 再判断能否作为连续1的结尾, 修改dp中首尾的值
-
利用count数组记录此次变化消去的长度可能和新添加的长度可能, 例如[1, 0, 1]变成[1, 1, 1]即消了两个长度1, 新增一个长度3的可能