• 【LeetCode】309c:最长优雅子数组



    原题链接: 309c:最长优雅子数组

    题目大意

    给你一个由 整数组成的数组 nums

    如果 nums 的子数组中位于 不同 位置的每对元素按位(AND)运算的结果等于 0 ,则称该子数组为 优雅 子数组。

    返回 最长 的优雅子数组的长度。

    子数组 是数组中的一个 连续 部分。

    **注意:**长度为 1 的子数组始终视作优雅子数组。
    示例 1:

    输入:nums = [1,3,8,48,10]
    输出:3
    解释:最长的优雅子数组是 [3,8,48] 。子数组满足题目条件:
    - 3 AND 8 = 0
    - 3 AND 48 = 0
    - 8 AND 48 = 0
    可以证明不存在更长的优雅子数组,所以返回 3 。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    示例 2:

    输入:nums = [3,1,5,11,13]
    输出:1
    解释:最长的优雅子数组长度为 1 ,任何长度为 1 的子数组都满足题目条件。
    
    • 1
    • 2
    • 3

    数据范围:

    1 <= nums.length <= 10^5
    1 <= nums[i] <= 10^9
    
    • 1
    • 2

    思路

    周赛时用的DP做法,但仍然较为暴力。用状态f[i]表示以位置i为结尾的最长优雅子数组s的长度。那么对于新的位置i+1,只需要对比nums[i + 1]s每个数的与状态(check()函数),若符合要求则尝试更新f[i+1],直接break;若不符合要求,则逐渐从s中抛弃左边的部分数字,对比nums[i + 1]s右子串每个数的与状态,继续尝试更新f[i+1],有更新可直接break。

    代码

    class Solution {
    public:
        bool check(vector<int>& nums, int l, int r){
            for(int i = l; i < r; i ++ ){
                if((nums[r] & nums[i]) == 0) continue;
                else return false;
            }
            
            return true;
        }
        
        int longestNiceSubarray(vector<int>& nums) {
            int n = nums.size();
            const int N = n + 10;
            int res = 1;
            int f[N];
            for(int i = 0; i < n; i ++ ) f[i] = 1;
            
            for(int i = 1; i < n; i ++ ){
                for(int j = i - 1 - f[i - 1] + 1; j <= i; j ++ ){
                    if(check(nums, j, i )){
                        f[i] = max(f[i], i - j + 1);
                        break;
                    }
                }
                
               
            }
            for(int i = 0; i < n; i ++ ){
                res = max(res, f[i]);
            }
            
            return res;
    
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    时间复杂度

    最差为 O ( n k 2 ) O(nk^2) O(nk2),其中k为以每个位置为结尾的最长优雅数组的平均长度,最好为 O ( n k ) O(nk) O(nk)

    思路2

    滑动窗口,用状态变量维护窗口内的合法性。其中状态变量可以用数组或一个数(位运算)。
    由于数的范围在1到10^9,可用31位二进制数来表示状态。可直接开状态数组cnt[40]来表示当前窗口内的各个位上的1的数量,若符合多个数与为0的要求,则每个位置上的1的数量不超过1。其中双指针i一直往前走,j在左边不断维护窗口合法性,若不合法则往右移动,移动结束后j到i这段区间满足要求,每次更新答案(res = max(res, i - j + 1))。
    若用一个int变量表示状态,可使用位运算。

    代码2

    class Solution {
    public:
        int longestNiceSubarray(vector<int>& nums) {
            int cnt[40] = {0};
            int res = 0;
            for(int i = 0, j = 0, tot = 0; i < nums.size(); i ++ ){
                for(int k = 0; k < 31; k ++ ){
                    if(nums[i] >> k & 1){
                        if(++ cnt[k] > 1) tot ++;
                    }
                }
                while(tot){
                    for(int k = 0; k < 31; k ++ ){
                        if(nums[j] >> k & 1){
                            if(-- cnt[k] == 1) tot -- ;
                        }
                    }
                    j ++ ;
                }
    
                res = max(res, i - j + 1);
            }
    
            return res;
        }
    };
    // 位运算
    class Solution {
    public:
        int longestNiceSubarray(vector<int>& nums) {
            int cnt[40] = {0};
            int res = 0;
            for(int i = 0, j = 0, state = 0; i < nums.size(); i ++ ){
                while(state & nums[i]){
                	// j++,从state中去除nums[j]的1
                    state ^= nums[j ++ ]; 
                }
                state |= nums[i]; // state加入nums[i]
    
                res = max(res, i - j + 1);
            }
    
            return res;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
  • 相关阅读:
    Parasoft Jtest 2023.1
    基于二次规划优化的OFDM系统PAPR抑制算法的matlab仿真
    Java Class09
    多年锤炼,迈向Kata 3.0 !走进开箱即用的安全容器体验之旅| 龙蜥技术
    STM32控制机械臂与传感器:整合ESP32通讯、Spark与人工智能优化的智能制造解决方案(代码说明)
    HTTP 抓包工具——Fiddler项目实战
    秋招面试!学历不是问题!大专老哥浅谈阿里/腾讯/京东Java后端面试经历,轻松上岸入职京东!
    [CakeCTF2022-09-04]CakeGEAR-Writeup
    【selenium】动作链接 ActionChains
    [网鼎杯2018]Unfinish-1|SQL注入|二次注入
  • 原文地址:https://blog.csdn.net/whq___/article/details/126823895