题目链接 LeetCode 1562. 查找大小为 M 的最新分组
题意:
给你一个数组 arr
,该数组表示一个从 1
到 n
的数字排列。有一个长度为 n
的二进制字符串,该字符串上的所有位最初都设置为 0
。
在从 1
到 n
的每个步骤 i
中(假设二进制字符串和 arr
都是从 1
开始索引的情况下),二进制字符串上位于位置 arr[i]
的位将会设为 1
。
给你一个整数 m
,请你找出二进制字符串上存在长度为 m
的一组 1
的最后步骤。一组 1
是一个连续的、由 1
组成的子串,且左右两边不再有可以延伸的 1
。
返回存在长度 恰好 为 m
的 一组 1
的最后步骤。如果不存在这样的步骤,请返回 -1
。
输入:arr = [3,5,1,2,4], m = 1
输出:4
解释:
步骤 1:"00100",由 1 构成的组:["1"]
步骤 2:"00101",由 1 构成的组:["1", "1"]
步骤 3:"10101",由 1 构成的组:["1", "1", "1"]
步骤 4:"11101",由 1 构成的组:["111", "1"]
步骤 5:"11111",由 1 构成的组:["11111"]
存在长度为 1 的一组 1 的最后步骤是步骤 4 。
解题思路:
从评论区里找大神的滑动窗口合并
思路: left[i] 数组表示 第 i 位置左边连续的1的个数 , right[i] 表示 第 i 位置右边连续1 的个数
cnt[i] 就是记录i个1相连的数的个数
class Solution {
/**
* @param Integer[] $arr
* @param Integer $m
* @return Integer
*/
function findLatestStep($arr, $m) {
$n = count($arr);
$ans = -1;
$cnt = array();
$left = array();
$right = array();
for($i = 0; $i <= $n+1; $i++) {
$cnt[$i] = 0; // 记录连续1长度为i的个数
$left[$i] = 0; // i位置左边连续1的个数
$right[$i] = 0; // i位置右边连续1的个数
}
for($i = 0; $i < $n; $i++) {
$x = $arr[$i]; // 第x 个位置
$k = $left[$x-1] + 1 + $right[$x+1]; // 插入后长度
$left[$x + $right[$x+1]] = $k; // 最难理解的部分
$right[$x - $left[$x-1]] = $k; // x - 左边长度的位置 右边连续为1的长度修改为k
$cnt[$left[$x-1]]--; // x左边的连续1长度 减去
$cnt[$right[$x+1]]--; // x右边边的连续1长度 减去
$cnt[$k]++; // 新生成的长度加1
if(isset($cnt[$m]) && $cnt[$m] > 0) {
$ans = $i + 1;
}
}
return $ans;
}
}
修改后,将两个数组缩减成 1个数组,使用数组记录当前点连续1的长度
class Solution {
/**
* @param Integer[] $arr
* @param Integer $m
* @return Integer
*/
function findLatestStep($a, $m) {
$n = count($a);
$cnt = array();
$h = array();
$ans = -1;
for($i = 0; $i <= $n+1; $i++) {
$cnt[$i] = 0;
$h[$i] = 0;
}
for($i = 0; $i < $n; $i++) {
$x = $a[$i];
$k = $h[$x-1] + 1 + $h[$x+1];
$cnt[$h[$x-1]]--;
$cnt[$h[$x+1]]--;
$h[$x - $h[$x-1]] = $k; // 修改
$h[$x + $h[$x+1]] = $k;
$cnt[$k]++;
if(isset($cnt[$m]) && $cnt[$m] > 0) {
$ans = $i + 1;
}
}
return $ans;
}
}