力扣2401. 最长优雅子数组
这一题的大意是说给出一个数组,要求找到一个子数组,使得子数组中的所有元素互相按位与的结果都为0,先让我们找最大的子数组的长度。
首先我们必须清楚什么是按位与&
可以看这一片文章:
按位与,左移,右移运算解析
只有两个数在同一位上都是1,结果才是1,否则就是0.
那么题目的意思就是必须保证子数组中每一个元素的二进制展开,展开后每一位都没有相同为1的位,如果有一个位它们都是1,那么结果一定不为0
因此我们要想办法看如何能够让新进入数组中的元素,与数组内的元素的按位与操作是否等于0.
这里仍然要进行位运算。
我们用mask=0来记录窗口中所有数的1位占用情况即看各个位是否被占用为1.
刚开始mask=0,新进来一位,可以通过|运算来把新进来的元素的为1的位标记为占用
|是按位或的意思,它表示只要有一个两个数的同一位只要有一个为1结果就为1。
我们可以用它来把元素中出现为1的位做标记。
mask|=nums[l];
这样就会把nums[l]中的所有位可能为1的标记在mask里面,下面就可以用mask去和新的nums[r]做&,来判断是否会为0或不为0.
如果出现冲突比如新进来的一个nums[r]与mask&的结果不为0,那么我们需要左移左指针,将左边的元素占据1位的移除,直到新进来的nums[r]与mask&的结果为0
这里用到^(按位异或,相同为0,不同为1)
实际上我觉得,只要清楚这几个位运算的操作的含义,这一题就是一道简单的滑动窗口题
通过|运算符不断的把新的元素放入mask,当出现冲突时把最左侧元素移走,直到数组合法,在移动的过程中不断地更新ans,找出最大的ans即可。
完整代码如下:
class Solution {
public:int longestNiceSubarray(vector<int>& nums) {int n=nums.size();int l=0;int r=0;int ans=0;int mask=0;while(r<n){while((mask&nums[r])!=0){mask^=nums[l];l++;}mask|=nums[r];ans=max(ans,r-l+1);r++;}return ans;}
};
注意:while((mask&nums[r])!=0)这里必须加括号,因为
&(按位与)的优先级 比比较运算符 != 低!
时间复杂度O(n)