leetcode每日一题:最大或值
题目
给你一个下标从 0 开始长度为 n
的整数数组 nums
和一个整数 k
。每一次操作中,你可以选择一个数并将它乘 2
。
你最多可以进行 k
次操作,请你返回 nums[0] | nums[1] | ... | nums[n - 1]
的最大值。
a | b
表示两个整数 a
和 b
的 按位或 运算。
示例 1:
输入:nums = [12,9], k = 1
输出:30
解释:如果我们对下标为 1 的元素进行操作,新的数组为 [12,18] 。此时得到最优答案为 12 和 18 的按位或运算的结果,也就是 30 。
示例 2:
输入:nums = [8,1,2], k = 2
输出:35
解释:如果我们对下标 0 处的元素进行操作,得到新数组 [32,1,2] 。此时得到最优答案为 32|1|2 = 35 。
提示:
1 <= nums.length <= 105
1 <= nums[i] <= 109
1 <= k <= 15
思路
考虑了挺久,看到方法最后的返回值是long
,才反应过来。本题其实有个隐含的条件没有说,就是选择1个数乘以2之后,是可以超出int范围的。有了这个条件之后,就豁然开朗了。那要让最后的或值最大,肯定要把这k次操作用在同一个数字上。因为每次乘以2的操作,相当于二进制数的左移1位,选择同一个数左移,才能把最高的1移动到尽量靠左,即更加高位的位置,让整体数值最大。
接下来就是在遍历的过程中,如何快速计算。对于每个数,我们要计算这个数左移k位,跟剩余其他数值的或值。为了避免重复计算,我们定义2个数组prefix[]
和suffix[]
,prefix[i]
代表nums[0, i-1]
的或值,suffix[i]
代表nums[i+1, n-1]
的或值。可以运用类似前缀和的方法,预先计算好这2个数组,然后再遍历nums
计算最大或值。这里有一个小技巧,对prefix[]
的计算,由于是从前往后遍历的,可以跟nums
的遍历放在同一个for循环中,这样可以减少一次遍历,虽然时间复杂度不变,不过也可以节省一些执行时间。
图解
代码
public long maximumOr(int[] nums, int k) {
int n = nums.length;
// 后缀 or 结果
int[] suffix = new int[n];
for (int i = n - 1; i >= 1; i--) {
suffix[i-1] = suffix[i] | nums[i];
}
long ans = 0;
long prefix = 0;
for (int i = 0; i < n; i++) {
ans = Math.max(ans, prefix | ((long) nums[i] << k) | suffix[i]);
prefix |= (long) nums[i];
}
return ans;
}
优化
上述方法中,开了2个长度为n的数组prefix[]
和suffix[]
,我们想办法优化。最直接可以想到的是,我们对nums
所有的值先做1次or
计算,得到orResult
,然后在遍历到某个值num
的时候,通过异或预算,去除掉这个num
的影响,这样就获的了去除当前num
,剩余所有值的或结果。
但是这样会存在一个问题:对于num
的二进制表示中所有为1的位,异或运算后都变成了0,如果这1位其他数是有1的,那么就多去除了。所以,我们还需要计算一个值fixed
,代表在这1位,至少存在2个数的二进制表示为1,那么无论结果选择对那个num
进行左移,这1位固定为1,我们在异或计算后,再次或运算fixed
,就可以得到真正的,去除当前num
后,剩余数值的或值。
优化后代码
public long maximumOr(int[] nums, int k) {
long orResult = 0;
// 如果多个数值在某1位是1,那么无论这个数是否做位移,or的结果这1位一定是1
long fixed = 0;
for (int num : nums) {
fixed |= orResult & num;
orResult |= num;
}
// 遍历的时候,通过 ^num 把这一位的数值排除掉,同时 |fixed 避免多排除的影响
long ans = 0;
for (int num : nums) {
ans = Math.max(ans, (orResult ^ num) | fixed | ((long)num<<k));
}
return ans;
}
耗时
leetcode每日一题:最大或值的更多相关文章
- 【python】Leetcode每日一题-逆波兰表达式求值
[python]Leetcode每日一题-逆波兰表达式求值 [题目描述] 根据 逆波兰表示法,求表达式的值. 有效的算符包括 +.-.*./ .每个运算对象可以是整数,也可以是另一个逆波兰表达式. 说 ...
- 【JavaScript】Leetcode每日一题-在D天内送包裹的能力
[JavaScript]Leetcode每日一题-在D天内送包裹的能力 [题目描述] 传送带上的包裹必须在 D 天内从一个港口运送到另一个港口. 传送带上的第 i 个包裹的重量为 weights[i] ...
- 【JavaScript】Leetcode每日一题-青蛙过河
[JavaScript]Leetcode每日一题-青蛙过河 [题目描述] 一只青蛙想要过河. 假定河流被等分为若干个单元格,并且在每一个单元格内都有可能放有一块石子(也有可能没有). 青蛙可以跳上石子 ...
- 【JavaScript】Leetcode每日一题-平方数之和
[JavaScript]Leetcode每日一题-平方数之和 [题目描述] 给定一个非负整数 c ,你要判断是否存在两个整数 a 和 b,使得 a2 + b2 = c . 示例1: 输入:c = 5 ...
- 【JavaScript】Leetcode每日一题-二叉搜索树的范围和
[JavaScript]Leetcode每日一题-二叉搜索树的范围和 [题目描述] 给定二叉搜索树的根结点 root,返回值位于范围 [low, high] 之间的所有结点的值的和. 示例1: 输入: ...
- 【JavaScript】Leetcode每日一题-递增顺序搜索树
[JavaScript]Leetcode每日一题-递增顺序搜索树 [题目描述] 给你一棵二叉搜索树,请你 按中序遍历 将其重新排列为一棵递增顺序搜索树,使树中最左边的节点成为树的根节点,并且每个节点没 ...
- 【python】Leetcode每日一题-寻找旋转排序数组中的最小元素
[python]Leetcode每日一题-寻找旋转排序数组中的最小元素 [题目描述] 已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组.例如,原数组nums ...
- 【JavaScript】Leetcode每日一题-矩形区域不超过K的最大值和
[JavaScript]Leetcode每日一题-矩形区域不超过K的最大值和 [题目描述] 给你一个 m x n 的矩阵 matrix 和一个整数 k ,找出并返回矩阵内部矩形区域的不超过 k 的最大 ...
- 【JavaScript】【KMP】Leetcode每日一题-实现strStr()
[JavaScript]Leetcode每日一题-实现strStr() [题目描述] 实现 strStr() 函数. 给你两个字符串 haystack 和 needle ,请你在 haystack 字 ...
- 【JavaScript】Leetcode每日一题-移除元素
[JavaScript]Leetcode每日一题-移除元素 [题目描述] 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度. 不要使用 ...
随机推荐
- ids4-startup
https://stackoverflow.com/questions/28418360/jwt-json-web-token-audience-aud-versus-client-id-whats- ...
- 通过Nginx反向代理配置/.well-known/pki-validation/fileauth.txt步骤实例
最近在某云平台上申请了SSL证书(https),SSL证书申请或者续期过程中需要进行域名验证. 如果域名验证类型选择[文件]方式,等你提交申请后,要在目标域名对应的服务端上传一个文件(通常是一个.tx ...
- oracle下批量增加序列值
感谢renjixinchina分享 原文链接http://blog.itpub.net/15747463/viewspace-751593/ oracle下批量增加序列值.批量滚动序列 declare ...
- Luogu P5663 CSP-J2019 加工零件 题解 [ 绿 ] [ 分层图最短路 ]
加工零件:非常好的一道图论题.CCF 普及组的题目大概也只有图论出的比较巧妙了. 题意简述:给你一张无向图,\(q\) 次询问,判断是否存在一条从 \(a\) 到 \(1\) 且长度为 \(L\) 的 ...
- AI 时代 UI 设计的哲学与伦理
无论是在桌面.移动应用,还是未来可能出现的全新形态中,空间直觉始终是人类在数字世界中导航的根本. 丹尼尔·罗德里格斯 图片来源:维基百科 想象一下,踏入1427年佛罗伦萨圣母玛利亚诺维拉教堂昏暗的光线 ...
- 用 C# 插值字符串处理器写一个 sscanf
插值字符串处理器 C# 有一个特性叫做插值字符串,使用插值字符串,你可以自然地往字符串里面插入变量的值,比如:$"abc{x}def",这一改以往通过 string.Format ...
- Docker安装mongoDB及使用教程
一.mongoDB是什么? MongoDB是一个NoSQL的非关系型数据库 ,支持海量数据存储,高性能的读写. mongoDB的特点(或使用场景) 1.支持存储海量数据:(例如:直播中的打赏数据): ...
- docker - [10] 容器数据卷
将应用和环境打包成一个镜像,然后发布启动就成为一个容器了. 一.什么是容器数据卷 容器数据卷(Container Data Volumes)是Docker管理的一种特殊类型的存储区域,它为容器提供 ...
- Linux - centos6.6升级openssh9.7p1
一.注意事项 1.任何会被修改的配置文件都要提前备份 2.每一步操作都要记录 3.提前预演,知道可能遇到的问题,以及对应的解决方法,能够在生产环境上升级时,更快完成操作. 4.一开始用来操作的ssh会 ...
- pnpm : 无法加载文件 \AppData\Roaming\npm\pnpm.ps1,因为在此系统上禁止运行脚本。
1. 安装pnpm npm install -g pnpm #安装 pnpm pnpm --version #查看pnpm版本 安装完成后查看版本时报错 pnpm : 无法加载文件 C:\Users\ ...