LeetCode——2411. 按位或最大的最小子数组长度
通过万岁!!!
- 题目:给你一个数字nums,里面全是正数,然后让你输入一个数字res,res[i]的值表示nums[i]到nums[i+res[i]]这些值进行按二进制或,可以得到一个最大值。res[i]的值最小,也就是说nums[i+res[i]]右边的那些数组,或不或不影响我的到的这个最大值。
- 思路:或就是存在1就是1,所以我们尽可能的要找到每个位的1的位置。注意这个数字小于10的9次方,那换成二进制32位就够了。我们应该弄一个二维数组32行,n列。这样就能把n个数都的二进制都用二维数组表示出来。到第i个数的时候,我们要看i这个数以及看右边的数的二进制,哪些能让32位中的某一个能先到1。这肯定能找到很多数字,因为我们有32位么。这些数字的最大的那个,就是右边的界限。右边的界限-i+1就是我们的res[i]了。
- 进阶思路:我们可以发现,这个比较浪费空间,其实我们用一个132的数组就够了,然后从右边开始往左边走下标设为i。132的数组中,第j个元素存储的是i右边的元素,二进制中,第j位最先为1的下标是多少。这样我们遍历到i的时候,右侧的值我们都在这个1*32的数组中,并且i判断完了以后,把i更新到数组中。这样空间复杂度就降下来了。伪代码binary数组大小为32,初始化为全为0,将nums[i]这个数字转成二进制。然后遍历,遇到第j位为1则binary[j]=i,这样binary[j]中存的就是离i最近的那个第j位是1的数字的下标了。对二进制遍历的时候,每次都要更新下maxIdx,maxIdx = max(maxIdx, binary[j])。maxIdx在每次i的循环中初始化为i或者0即可。
● 技巧:滑动窗口、位运算
java代码
class Solution {public int[] smallestSubarrays(int[] nums) {int[] res = new int[nums.length];// binary表示数组中数字转到二进制以后,从右边开始第j个二进制为1的这个数字的下标int[] binary = new int[31];// i表示第几个数字for (int i = nums.length - 1; i >= 0; --i) {int maxIdx = i;int curr = nums[i];for (int j = 0; j < binary.length; ++j) {// 先把自己更新进去if (curr % 2 == 1) {binary[j] = i;}// 已知的为1的最近的数字maxIdx = Math.max(maxIdx, binary[j]);curr /= 2;}res[i] = maxIdx - i + 1;}return res;}
}
- 总结:题目还是挺有意思的,特别是进阶思路,从右往左循环。