题目

2680. 最大或值

给你一个下标从 0 开始长度为 n 的整数数组 nums 和一个整数 k 。每一次操作中,你可以选择一个数并将它乘 2

你最多可以进行 k 次操作,请你返回 nums[0] | nums[1] | ... | nums[n - 1] 的最大值。

a | b 表示两个整数 ab按位或 运算。

示例 1:

  1. 输入:nums = [12,9], k = 1
  2. 输出:30
  3. 解释:如果我们对下标为 1 的元素进行操作,新的数组为 [12,18] 。此时得到最优答案为 12 18 的按位或运算的结果,也就是 30

示例 2:

  1. 输入:nums = [8,1,2], k = 2
  2. 输出:35
  3. 解释:如果我们对下标 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循环中,这样可以减少一次遍历,虽然时间复杂度不变,不过也可以节省一些执行时间。

图解

代码

  1. public long maximumOr(int[] nums, int k) {
  2. int n = nums.length;
  3. // 后缀 or 结果
  4. int[] suffix = new int[n];
  5. for (int i = n - 1; i >= 1; i--) {
  6. suffix[i-1] = suffix[i] | nums[i];
  7. }
  8. long ans = 0;
  9. long prefix = 0;
  10. for (int i = 0; i < n; i++) {
  11. ans = Math.max(ans, prefix | ((long) nums[i] << k) | suffix[i]);
  12. prefix |= (long) nums[i];
  13. }
  14. return ans;
  15. }

优化

​ 上述方法中,开了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后,剩余数值的或值。

优化后代码

  1. public long maximumOr(int[] nums, int k) {
  2. long orResult = 0;
  3. // 如果多个数值在某1位是1,那么无论这个数是否做位移,or的结果这1位一定是1
  4. long fixed = 0;
  5. for (int num : nums) {
  6. fixed |= orResult & num;
  7. orResult |= num;
  8. }
  9. // 遍历的时候,通过 ^num 把这一位的数值排除掉,同时 |fixed 避免多排除的影响
  10. long ans = 0;
  11. for (int num : nums) {
  12. ans = Math.max(ans, (orResult ^ num) | fixed | ((long)num<<k));
  13. }
  14. return ans;
  15. }

耗时

leetcode每日一题:最大或值的更多相关文章

  1. 【python】Leetcode每日一题-逆波兰表达式求值

    [python]Leetcode每日一题-逆波兰表达式求值 [题目描述] 根据 逆波兰表示法,求表达式的值. 有效的算符包括 +.-.*./ .每个运算对象可以是整数,也可以是另一个逆波兰表达式. 说 ...

  2. 【JavaScript】Leetcode每日一题-在D天内送包裹的能力

    [JavaScript]Leetcode每日一题-在D天内送包裹的能力 [题目描述] 传送带上的包裹必须在 D 天内从一个港口运送到另一个港口. 传送带上的第 i 个包裹的重量为 weights[i] ...

  3. 【JavaScript】Leetcode每日一题-青蛙过河

    [JavaScript]Leetcode每日一题-青蛙过河 [题目描述] 一只青蛙想要过河. 假定河流被等分为若干个单元格,并且在每一个单元格内都有可能放有一块石子(也有可能没有). 青蛙可以跳上石子 ...

  4. 【JavaScript】Leetcode每日一题-平方数之和

    [JavaScript]Leetcode每日一题-平方数之和 [题目描述] 给定一个非负整数 c ,你要判断是否存在两个整数 a 和 b,使得 a2 + b2 = c . 示例1: 输入:c = 5 ...

  5. 【JavaScript】Leetcode每日一题-二叉搜索树的范围和

    [JavaScript]Leetcode每日一题-二叉搜索树的范围和 [题目描述] 给定二叉搜索树的根结点 root,返回值位于范围 [low, high] 之间的所有结点的值的和. 示例1: 输入: ...

  6. 【JavaScript】Leetcode每日一题-递增顺序搜索树

    [JavaScript]Leetcode每日一题-递增顺序搜索树 [题目描述] 给你一棵二叉搜索树,请你 按中序遍历 将其重新排列为一棵递增顺序搜索树,使树中最左边的节点成为树的根节点,并且每个节点没 ...

  7. 【python】Leetcode每日一题-寻找旋转排序数组中的最小元素

    [python]Leetcode每日一题-寻找旋转排序数组中的最小元素 [题目描述] 已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组.例如,原数组nums ...

  8. 【JavaScript】Leetcode每日一题-矩形区域不超过K的最大值和

    [JavaScript]Leetcode每日一题-矩形区域不超过K的最大值和 [题目描述] 给你一个 m x n 的矩阵 matrix 和一个整数 k ,找出并返回矩阵内部矩形区域的不超过 k 的最大 ...

  9. 【JavaScript】【KMP】Leetcode每日一题-实现strStr()

    [JavaScript]Leetcode每日一题-实现strStr() [题目描述] 实现 strStr() 函数. 给你两个字符串 haystack 和 needle ,请你在 haystack 字 ...

  10. 【JavaScript】Leetcode每日一题-移除元素

    [JavaScript]Leetcode每日一题-移除元素 [题目描述] 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度. 不要使用 ...

随机推荐

  1. ids4-startup

    https://stackoverflow.com/questions/28418360/jwt-json-web-token-audience-aud-versus-client-id-whats- ...

  2. 通过Nginx反向代理配置/.well-known/pki-validation/fileauth.txt步骤实例

    最近在某云平台上申请了SSL证书(https),SSL证书申请或者续期过程中需要进行域名验证. 如果域名验证类型选择[文件]方式,等你提交申请后,要在目标域名对应的服务端上传一个文件(通常是一个.tx ...

  3. oracle下批量增加序列值

    感谢renjixinchina分享 原文链接http://blog.itpub.net/15747463/viewspace-751593/ oracle下批量增加序列值.批量滚动序列 declare ...

  4. Luogu P5663 CSP-J2019 加工零件 题解 [ 绿 ] [ 分层图最短路 ]

    加工零件:非常好的一道图论题.CCF 普及组的题目大概也只有图论出的比较巧妙了. 题意简述:给你一张无向图,\(q\) 次询问,判断是否存在一条从 \(a\) 到 \(1\) 且长度为 \(L\) 的 ...

  5. AI 时代 UI 设计的哲学与伦理

    无论是在桌面.移动应用,还是未来可能出现的全新形态中,空间直觉始终是人类在数字世界中导航的根本. 丹尼尔·罗德里格斯 图片来源:维基百科 想象一下,踏入1427年佛罗伦萨圣母玛利亚诺维拉教堂昏暗的光线 ...

  6. 用 C# 插值字符串处理器写一个 sscanf

    插值字符串处理器 C# 有一个特性叫做插值字符串,使用插值字符串,你可以自然地往字符串里面插入变量的值,比如:$"abc{x}def",这一改以往通过 string.Format ...

  7. Docker安装mongoDB及使用教程

    一.mongoDB是什么? MongoDB是一个NoSQL的非关系型数据库 ,支持海量数据存储,高性能的读写. mongoDB的特点(或使用场景) 1.支持存储海量数据:(例如:直播中的打赏数据): ...

  8. docker - [10] 容器数据卷

    将应用和环境打包成一个镜像,然后发布启动就成为一个容器了. 一.什么是容器数据卷   容器数据卷(Container Data Volumes)是Docker管理的一种特殊类型的存储区域,它为容器提供 ...

  9. Linux - centos6.6升级openssh9.7p1

    一.注意事项 1.任何会被修改的配置文件都要提前备份 2.每一步操作都要记录 3.提前预演,知道可能遇到的问题,以及对应的解决方法,能够在生产环境上升级时,更快完成操作. 4.一开始用来操作的ssh会 ...

  10. pnpm : 无法加载文件 \AppData\Roaming\npm\pnpm.ps1,因为在此系统上禁止运行脚本。

    1. 安装pnpm npm install -g pnpm #安装 pnpm pnpm --version #查看pnpm版本 安装完成后查看版本时报错 pnpm : 无法加载文件 C:\Users\ ...