题目链接如下:https://leetcode.cn/problems/maximum-or/
该题用到了贪心+前后缀分解的方法(对于我这个小白来说挺难想的)
关于前导知识:一个数乘以2相当于一个数左移1位,比如对于2,它的二进制为10,左移以为相当于100,为4,我们可以根据C++语言中<<符号来实现该情况,
举例说明:int x=2,y; y=x<<1;则y=4;
同理:对于一个数来说,如果移动k位,则可以如下来写: int x=2,y; y=x<<k;
回到该题,我们可以这样分析,对于nums数组,假如一个数在这些数中的二进制位数最大,我们就一直可以让它左移,由于是或运算,不存在进一的情况,选中一个最大值,一直左移取或运算就可以取得最大值,根据贪心策略,如果选中一个数一直取左移,可以得到取或的最大值。
当然,这一步肯定好想,但是对于二进制位数相同的情况呢,对于题中案例的9和12,并不选择12,而是选择9,我们可以将其拆分成二进制12 —> 1100,9—>1001,发现如果9左移后取或较大,
下面就开始拆解二进制了.
请看示例:我们可以定义一个数组来维护后缀表达式(即维护第i位及之后的取或运算),定义一个前缀中间变量,用来维护i位之前(不包含i)的取或运算,通过取第i位数的左移位运算,设置中间变量,取得最大值,图解如下(三段论):
代码如下:
class Solution {
public:
typedef long long LL;
long long maximumOr(vector<int>& nums, int k) {
vector<LL>v(nums.size()+1);
for(int i=nums.size()-1;i>=0;i--)v[i]=v[i+1]|nums[i];//维护后缀表达式
LL ans=-1;//定义结果
LL tmp=0;//定义前缀表达式
for(int i=0;i<nums.size();i++){
ans=max(ans,tmp|((LL)nums[i]<<k)|v[i+1]);//更新三段
tmp|=nums[i];//前缀表达式
}
return ans;
}
LL max(LL x,LL y){
if(x>y)return x;
return y;
}
};