leetcode
leetcode 2451 ~ 2500
将数组分割成最多数目的子数组

将数组分割成最多数目的子数组

难度:

标签:

题目描述

You are given an array nums consisting of non-negative integers.

We define the score of subarray nums[l..r] such that l <= r as nums[l] AND nums[l + 1] AND ... AND nums[r] where AND is the bitwise AND operation.

Consider splitting the array into one or more subarrays such that the following conditions are satisfied:

  • Each element of the array belongs to exactly one subarray.
  • The sum of scores of the subarrays is the minimum possible.

Return the maximum number of subarrays in a split that satisfies the conditions above.

A subarray is a contiguous part of an array.

 

Example 1:

Input: nums = [1,0,2,0,1,2]
Output: 3
Explanation: We can split the array into the following subarrays:
- [1,0]. The score of this subarray is 1 AND 0 = 0.
- [2,0]. The score of this subarray is 2 AND 0 = 0.
- [1,2]. The score of this subarray is 1 AND 2 = 0.
The sum of scores is 0 + 0 + 0 = 0, which is the minimum possible score that we can obtain.
It can be shown that we cannot split the array into more than 3 subarrays with a total score of 0. So we return 3.

Example 2:

Input: nums = [5,7,1,3]
Output: 1
Explanation: We can split the array into one subarray: [5,7,1,3] with a score of 1, which is the minimum possible score that we can obtain.
It can be shown that we cannot split the array into more than 1 subarray with a total score of 1. So we return 1.

 

Constraints:

  • 1 <= nums.length <= 105
  • 0 <= nums[i] <= 106

代码结果

运行时间: 77 ms, 内存: 24.8 MB


/*
 * 思路:
 * 使用Java Stream API来实现类似的逻辑。
 * 我们可以通过 IntStream 来遍历数组,并在遇到 AND 运算结果为0时增加计数。
 */
import java.util.stream.IntStream;

public class Solution {
    public int maxSubarrays(int[] nums) {
        int[] andResult = {nums[0]};
        long count = IntStream.range(0, nums.length)
            .map(i -> andResult[0] &= nums[i])
            .filter(res -> res == 0)
            .count();
        return (andResult[0] == 0) ? (int) count : (int) count + 1;
    }
}

解释

方法:

题解通过遍历数组元素,并连续地对它们进行AND操作,直到结果变为0。一旦结果为0,意味着可以形成一个子数组,因此增加子数组的计数。然后重置AND操作的初始值重新开始。这个策略利用了AND操作的属性,即任何数与0进行AND操作的结果都为0。因此,最优策略是尽可能快地达到AND结果为0,从而最大化子数组的数量。整体方法是贪心策略,通过局部最优达到全局最优,即尽可能分割出多的子数组,使得每个子数组的AND结果尽可能小(优先达到0)。最后,如果数组中的所有元素AND的结果不为0,则至少可以形成1个子数组。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
为什么在AND操作结果变为0时,就可以确定形成一个子数组?这是否意味着在此之前的所有元素AND的结果必然是最小的?
在AND操作中,一旦结果变为0,意味着至少有一位在所有参与AND运算的元素中均为0。由于更多的元素参与AND运算只会让结果的位中的1变成0(从不会从0变回1),所以一旦达到0,继续添加新的元素不会让AND结果变回非0。因此,在结果首次变为0时形成一个子数组是合理的,这确保了在当前子数组的范围内,元素的AND结果是最小的(即0)。
🦆
如果数组中的一个数已经为0,算法是如何处理这种情况的?直接开始新的子数组还是如何?
如果数组中的一个数为0,则根据算法逻辑,该数与之前的AND结果进行AND运算后得到0。在这种情况下,算法会立即结束当前子数组的构建,并开始一个新的子数组。这是因为0与任何数进行AND运算的结果仍然为0,所以以0为分界点开始新的子数组是最优的分割方式。
🦆
在算法中,变量`a`被初始化为-1,这是否意味着我们假设所有输入的位宽相同,且均为32位整数?对于不同位宽的整数,这种初始化方法是否还适用?
变量`a`被初始化为-1,确实假设了所有整数的位宽相同,通常是32位。在-1的二进制表示中,所有位都是1。这种初始化方法在所有整数位宽相同的情况下是有效的,因为它代表了最大可能的位值。如果处理的整数位宽不同,这种方法可能不适用,因为对于更长的位宽,-1的表示将包含更多的1位,可能导致错误的AND结果。在这种情况下,应该根据实际的最大位宽来调整初始化的值。
🦆
算法是否考虑了数组中所有元素AND结果不为0的情况?在这种情况下,如何保证返回的子数组数目是最多的?
算法确实考虑了数组中所有元素AND结果不为0的情况。如果在整个数组遍历结束后,AND结果仍然不为0,算法通过确保至少返回1来处理这种情况。这意味着即便不能通过将AND结果变为0来进一步分割数组,至少整个数组可以作为一个子数组。这种方法确保了在无法通过AND操作进一步细分的情况下,至少有一个子数组,但不一定是最多的子数组数目,因为算法的目标是尽可能使AND结果尽快达到0,从而最大化子数组数量。

相关问题