【位运算】3097. 或值至少为 K 的最短子数组

简介: 【位运算】3097. 或值至少为 K 的最短子数组

本文涉及知识点

位运算

LeetCode3097. 或值至少为 K 的最短子数组 II

给你一个 非负 整数数组 nums 和一个整数 k 。

如果一个数组中所有元素的按位或运算 OR 的值 至少 为 k ,那么我们称这个数组是 特别的 。

请你返回 nums 中 最短特别非空 子数组

的长度,如果特别子数组不存在,那么返回 -1 。

示例 1:

输入:nums = [1,2,3], k = 2

输出:1

解释:

子数组 [3] 的按位 OR 值为 3 ,所以我们返回 1 。

示例 2:

输入:nums = [2,1,8], k = 10

输出:3

解释:

子数组 [2,1,8] 的按位 OR 值为 11 ,所以我们返回 3 。

示例 3:

输入:nums = [1,2], k = 0

输出:1

解释:

子数组 [1] 的按位 OR 值为 1 ,所以我们返回 1 。

提示:

1 <= nums.length <= 2 * 105

0 <= nums[i] <= 109

0 <= k <= 109

位运算

nums[l…x]的异或值,无论x有多少可能,其值最多log(iMax)种,如果值发生变化,至少加一个1,所有的二进制位变成1,就不会变化了。

队列index[i] 记录 升序记录所有( nums[x]&(1<

以j开始的子数组,只有结尾为x才方式变化。x 是index[i]中第一个大于j的元素。

代码

核心代码

class Solution {
public:
  int minimumSubarrayLength(vector<int>& nums, int k) {
    queue<int> index[31];
    for (int i = 0; i < nums.size(); i++)
    {
      for (int j = 0; j <= 30; j++)
      {
        const bool b = (1 << j) & nums[i];
        if (b) {
          index[j].emplace(i);
        }
      }
    }
    int iRet = nums.size() + 1;
    for (int i = 0; i < nums.size(); i++)
    {     
      int cur = nums[i];
      if (cur >= k) { return 1; };
      set<int> setNext;
      for (int j = 0; j <= 30; j++)
      {
        if (index[j].size()) {
          setNext.emplace(index[j].front());
        }
      }
      for (const auto& next : setNext) {
        cur |= nums[next];
        if (cur >= k) {
          iRet = min(iRet, next - i + 1);
          break;
        }
      }
      for (int j = 0; j <= 30; j++)
      {
        if (index[j].size() && (index[j].front() == i)) {
          index[j].pop();
        }
      }
    }
    return (iRet>nums.size())?-1: iRet;
  }
};

使用模板

class Solution {
public:
  int minimumSubarrayLength(vector<int>& nums, int k) {
    //模板代码
    vector<vector<pair<int, int>>> vNumIndex(nums.size());
    for (int i = 0; i < nums.size(); i++) {
      if (i) {
        for (const auto& [preNum, preIndex] : vNumIndex[i - 1]) {
          const int iNew = preNum | nums[i];
          if (vNumIndex[i].empty() || (vNumIndex[i].back().first != iNew)) {
            vNumIndex[i].emplace_back(make_pair(iNew, preIndex));
          }
          else {
            vNumIndex[i].back().second = preIndex;
          }
        }
      }
      if (vNumIndex[i].empty() || (vNumIndex[i].back().first != nums[i])) {
        vNumIndex[i].emplace_back(make_pair(nums[i], i));
      }
      else {
        vNumIndex[i].back().second = i;
      }
    }
    int iRet = INT_MAX;
    for (const auto& v : vNumIndex) {
      for (int i = 0; i < v.size(); i++) {
        if (v[v.size() - 1 - i].first >= k) {
          iRet = min(iRet, v.back().second - v[v.size() - 1 - i].second + 1);
          break;
        }
      }
    }
    return (INT_MAX == iRet) ? -1 : iRet;
  }
};

测试用例

template<class T>
void Assert(const T& t1, const T& t2)
{
    assert(t1 == t2);
}
template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{
    if (v1.size() != v2.size())
    {
        assert(false);
        return;
    }
    for (int i = 0; i < v1.size(); i++)
    {
        Assert(v1[i], v2[i]);
    }
}
int main()
{
  vector<int> nums;
  int k;
  {
    Solution sln;
    nums = { 1,2,32,21 }, k = 55;
    auto res = sln.minimumSubarrayLength(nums, k);
    Assert(3, res);
  }
  {
    Solution sln;
    nums = { 1, 2, 3 }, k = 2;
    auto res = sln.minimumSubarrayLength(nums, k);
    Assert(1, res);
  }
  {
    Solution sln;
    nums = { 2,1,8 }, k = 10;
    auto res = sln.minimumSubarrayLength(nums, k);
    Assert(3, res);
  }
  {
    Solution sln;
    nums = { 1,2 }, k = 0;
    auto res = sln.minimumSubarrayLength(nums, k);
    Assert(1, res);
  }
}


我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17

或者 操作系统:win10 开发环境: VS2022 C++17

如无特殊说明,本算法用**C++**实现。


相关文章
|
3月前
|
算法
【算法】位运算算法——判断字符是否唯一
【算法】位运算算法——判断字符是否唯一
|
5月前
|
算法
数据结构和算法——散列函数的构造方法(直接定址法、除留余数法、数字分析法、折叠法、平方取中法、ASCII码加和法、前三字符移位法)
数据结构和算法——散列函数的构造方法(直接定址法、除留余数法、数字分析法、折叠法、平方取中法、ASCII码加和法、前三字符移位法)
63 0
|
6月前
|
算法 测试技术 C#
【位运算 试填法】【推荐】3022. 给定操作次数内使剩余元素的或值最小
【位运算 试填法】【推荐】3022. 给定操作次数内使剩余元素的或值最小
|
6月前
|
人工智能 测试技术
【位运算 状态压缩 枚举子集】1178. 猜字谜
【位运算 状态压缩 枚举子集】1178. 猜字谜
|
6月前
|
存储 算法 测试技术
位运算、状态压缩、枚举子集汇总
位运算、状态压缩、枚举子集汇总
|
6月前
LeetCode题 338比特位计数,20有效的括号,415字符串相加
LeetCode题 338比特位计数,20有效的括号,415字符串相加
64 0
【每日挠头算法(4)】字符串相加|字符串相乘
【每日挠头算法(4)】字符串相加|字符串相乘
|
机器学习/深度学习 算法
268. 丢失的数字 :「排序」&「计数」&「原地哈希」&「数学」&「异或」
268. 丢失的数字 :「排序」&「计数」&「原地哈希」&「数学」&「异或」
|
算法
Leetcode 862. 和至少为 K 的最短子数组
给你一个整数数组 nums 和一个整数 k ,找出 nums 中和至少为 k 的 最短非空子数组 ,并返回该子数组的长度。如果不存在这样的 子数组 ,返回 -1 。
91 0
【每日一题Day41】生成交替二进制字符串的最小操作数 | 模拟 位运算
思路:长度一定的交替二进制字符串有两种可能性,以字符0开头的0101字符串和以字符1开头的1010字符串,因此只需要将字符串s与这两种字符串进行比较,记录不相同的字符个数,最后返回较小值即可
97 0
【每日一题Day41】生成交替二进制字符串的最小操作数 | 模拟 位运算