2411. 按位或最大的最小子数组长度
给你一个长度为 n
下标从 0 开始的数组 nums
,数组中所有数字均为非负整数。对于 0
到 n - 1
之间的每一个下标 i
,你需要找出 nums
中一个 最小 非空子数组,它的起始位置为 i
(包含这个位置),同时有 最大 的 按位或运算值 。
Bij
表示子数组 nums[i...j]
的按位或运算的结果,你需要找到一个起始位置为 i
的最小子数组,这个子数组的按位或运算的结果等于 max(Bik)
,其中 i <= k <= n - 1
。一个数组的按位或运算值是这个数组里所有数字按位或运算的结果。
请你返回一个大小为 n
的整数数组 answer
,其中 answer[i]
是开始位置为 i
,按位或运算结果最大,且 最短 子数组的长度。
子数组 是数组里一段连续非空元素组成的序列。
示例 1:
输入:nums = [1,0,2,1,3] 输出:[3,3,2,2,1] 解释: 任何位置开始,最大按位或运算的结果都是 3 。 - 下标 0 处,能得到结果 3 的最短子数组是 [1,0,2] 。 - 下标 1 处,能得到结果 3 的最短子数组是 [0,2,1] 。 - 下标 2 处,能得到结果 3 的最短子数组是 [2,1] 。 - 下标 3 处,能得到结果 3 的最短子数组是 [1,3] 。 - 下标 4 处,能得到结果 3 的最短子数组是 [3] 。 所以我们返回 [3,3,2,2,1] 。
示例 2:
输入:nums = [1,2] 输出:[2,1] 解释: 下标 0 处,能得到最大按位或运算值的最短子数组长度为 2 。 下标 1 处,能得到最大按位或运算值的最短子数组长度为 1 。 所以我们返回 [2,1] 。
提示:
n == nums.length
1 <= n <= 105
0 <= nums[i] <= 109
原站题解
cpp 解法, 执行用时: 100 ms, 内存消耗: 54.8 MB, 提交时间: 2023-09-18 17:38:34
class Solution { public: vector<int> smallestSubarrays(vector<int> &nums) { int n = nums.size(); vector<int> ans(n); for (int i = 0; i < n; ++i) { ans[i] = 1; for (int j = i - 1; j >= 0 && (nums[j] | nums[i]) != nums[j]; --j) { nums[j] |= nums[i]; ans[j] = i - j + 1; } } return ans; } // 更通用模板 vector<int> smallestSubarrays2(vector<int> &nums) { int n = nums.size(); vector<int> ans(n); vector<pair<int, int>> ors; // 按位或的值 + 对应子数组的右端点的最小值 for (int i = n - 1; i >= 0; --i) { ors.emplace_back(0, i); ors[0].first |= nums[i]; int k = 0; for (int j = 1; j < ors.size(); ++j) { ors[j].first |= nums[i]; if (ors[k].first == ors[j].first) ors[k].second = ors[j].second; // 合并相同值,下标取最小的 else ors[++k] = ors[j]; } ors.resize(k + 1); // 本题只用到了 ors[0],如果题目改成任意给定数字,可以在 ors 中查找 ans[i] = ors[0].second - i + 1; } return ans; } };
java 解法, 执行用时: 6 ms, 内存消耗: 56.9 MB, 提交时间: 2023-09-18 17:37:47
class Solution { public int[] smallestSubarrays(int[] nums) { var n = nums.length; var ans = new int[n]; for (var i = 0; i < n; ++i) { ans[i] = 1; for (var j = i - 1; j >= 0 && (nums[j] | nums[i]) != nums[j]; --j) { nums[j] |= nums[i]; ans[j] = i - j + 1; } } return ans; } // 更通用模板 public int[] smallestSubarrays2(int[] nums) { var n = nums.length; var ans = new int[n]; var ors = new ArrayList<int[]>(); // 按位或的值 + 对应子数组的右端点的最小值 for (int i = n - 1; i >= 0; --i) { ors.add(new int[]{0, i}); var k = 0; for (var or : ors) { or[0] |= nums[i]; if (ors.get(k)[0] == or[0]) ors.get(k)[1] = or[1]; // 合并相同值,下标取最小的 else ors.set(++k, or); } ors.subList(k + 1, ors.size()).clear(); // 本题只用到了 ors[0],如果题目改成任意给定数值,可以在 ors 中查找 ans[i] = ors.get(0)[1] - i + 1; } return ans; } }
python3 解法, 执行用时: 816 ms, 内存消耗: 32.4 MB, 提交时间: 2023-09-18 17:37:05
class Solution: def smallestSubarrays(self, nums: List[int]) -> List[int]: ans = [0] * len(nums) for i, x in enumerate(nums): ans[i] = 1 for j in range(i - 1, -1, -1): if (nums[j] | x) == nums[j]: break nums[j] |= x ans[j] = i - j + 1 return ans # 更通用模板 # 1. 求出所有子数组的按位或的结果,以及值等于该结果的子数组的个数。 # 2. 求按位或结果等于任意给定数字的子数组的最短长度/最长长度。 def smallestSubarrays2(self, nums: List[int]) -> List[int]: n = len(nums) ans = [0] * n ors = [] # 按位或的值 + 对应子数组的右端点的最小值 for i in range(n - 1, -1, -1): num = nums[i] ors.append([0, i]) k = 0 for p in ors: p[0] |= num if ors[k][0] == p[0]: ors[k][1] = p[1] # 合并相同值,下标取最小的 else: k += 1 ors[k] = p del ors[k + 1:] # 本题只用到了 ors[0],如果题目改成任意给定数值,可以在 ors 中查找 ans[i] = ors[0][1] - i + 1 return ans
golang 解法, 执行用时: 64 ms, 内存消耗: 8.6 MB, 提交时间: 2023-09-18 17:35:59
func smallestSubarrays(nums []int) []int { ans := make([]int, len(nums)) for i, x := range nums { ans[i] = 1 for j := i - 1; j >= 0 && nums[j]|x != nums[j]; j-- { nums[j] |= x ans[j] = i - j + 1 } } return ans } // 通用模板 func smallestSubarrays2(nums []int) []int { n := len(nums) ans := make([]int, n) type pair struct{ or, i int } ors := []pair{} // 按位或的值 + 对应子数组的右端点的最小值 for i := n - 1; i >= 0; i-- { num := nums[i] ors = append(ors, pair{0, i}) ors[0].or |= num k := 0 for _, p := range ors[1:] { p.or |= num if ors[k].or == p.or { ors[k].i = p.i // 合并相同值,下标取最小的 } else { k++ ors[k] = p } } ors = ors[:k+1] // 本题只用到了 ors[0],如果题目改成任意给定数字,可以在 ors 中查找 ans[i] = ors[0].i - i + 1 } return ans }
python3 解法, 执行用时: 492 ms, 内存消耗: 25.9 MB, 提交时间: 2022-11-09 14:29:08
class Solution: def smallestSubarrays(self, nums: List[int]) -> List[int]: n = len(nums) ans = [0] * n ors = [] # 按位或的值 + 对应子数组的右端点的最小值 for i in range(n - 1, -1, -1): num = nums[i] ors.append([0, i]) k = 0 for p in ors: p[0] |= num if ors[k][0] == p[0]: ors[k][1] = p[1] # 合并相同值,下标取最小的 else: k += 1 ors[k] = p del ors[k + 1:] # 本题只用到了 ors[0],如果题目改成任意给定数值,可以在 ors 中查找 ans[i] = ors[0][1] - i + 1 return ans
python3 解法, 执行用时: 288 ms, 内存消耗: 25.9 MB, 提交时间: 2022-11-09 14:27:43
class Solution: def smallestSubarrays(self, nums: List[int]) -> List[int]: ans = [0] * len(nums) for i, x in enumerate(nums): ans[i] = 1 for j in range(i - 1, -1, -1): if (nums[j] | x) == nums[j]: break nums[j] |= x ans[j] = i - j + 1 return ans