力扣训练5

2401. 最长优雅子数组

两个不同的数相与结果为0,那么这2个数一定没有一个同一位置的1,从左往右枚举,枚举时h滑动窗口维护一个当前所有数的或的结果(填充所有的1)遇上数时判断now是否为0

如果与当前记录的结果now相与为0,那么now或运算上这个数,右指针往前继续走
如果与当前记录的结果now相与不为0,那么加入的这个数不满足条件,需要将滑动窗口左边往右移,对于每一个离开窗口的数,用记录的窗口结果now与其做异或运算。

class Solution {
public:
    int longestNiceSubarray(vector<int>& nums) {
        int n = nums.size();
        int i = 0;
        if (n == 1) return 1;
        int j = i + 1;
        int ans = 1;
        long long now = nums[i];
        while (i < n && j < n) {
            while ((i < j) && ((now & nums[j]) != 0)) { // 滑动窗口左指针往后移
                now ^= nums[i]; // 剔除出去的数
                ++i;
            }
            now |= nums[j]; // 加入新的数
            ans = max(ans, j - i + 1); // 更新答案
            ++j;
        }
        return ans;
    }
};

  • 模拟即可。
  • 两字符串完全相同:必须有重复出现的字符才能交换,用哈希表判断是否存在出现次数大于等于2
  • 两字符串恰好两个位置不同:这两个位置上的元素必然交错相等。
  • class Solution {
    public:
        bool buddyStrings(string s, string goal) {
            
            if(s.size() != goal.size()) return false;
            vector<int> vt;
            unordered_map<char, int> hash;
            int res = 0;
            for(int i = 0; i < s.size(); i++) {
                hash[s[i]]++;
                res = max(res, hash[s[i]]);
                if(s[i]==goal[i]) continue;
                vt.push_back(i);
            }
            if(vt.empty()) return res >= 2;
            return vt.size()==2 && s[vt[0]] == goal[vt[1]] && s[vt[1]] == goal[vt[0]];
        }
    };

  • 167. 两数之和 II - 输入有序数组
  • 二分

  • 数组中找到两个数,使得它们的和等于目标值,可以首先固定第一个数,然后寻找第二个数,第二个数等于目标值减去第一个数的差。利用数组的有序性质,可以通过二分查找的方法寻找第二个数。为了避免重复寻找,在寻找第二个数时,只在第一个数的右侧寻找。

  • class Solution {
    public:
        vector<int> twoSum(vector<int>& numbers, int target) {
            for (int i = 0; i < numbers.size(); ++i) {
                int low = i + 1, high = numbers.size() - 1;
                while (low <= high) {
                    int mid = (high - low) / 2 + low;
                    if (numbers[mid] == target - numbers[i]) {
                        return {i + 1, mid + 1};
                    } else if (numbers[mid] > target - numbers[i]) {
                        high = mid - 1;
                    } else {
                        low = mid + 1;
                    }
                }
            }
            return {-1, -1};
        }
    };

    581. 最短无序连续子数组
  • 我们可以先把一个小的无序的区间找出来,即遍历中第一个不满足递增的位置和反向遍历中第一个不满足递减的位置。又因为无序区间内的最小值比第一区间所有值都大,最大值比第三区间所有值都小,所以我们可以简单找出一个无序区间,然后通过二分法快速找出最小需要排序区间的真正大小。

  • 二分法

  • class Solution {
    public:
        int findUnsortedSubarray(vector<int>& nums) {
            const int n = nums.size();
            int lhs = 0, rhs = n - 1;
            while(lhs + 1 < n && nums[lhs + 1] >= nums[lhs]) ++lhs; 
            if(lhs == n - 1) return 0;  
            while(nums[rhs - 1] <= nums[rhs]) --rhs; 
            auto itL = nums.begin() + lhs, itR = nums.begin() + rhs + 1; 
            int minn = *min_element(itL, itR);   
            int maxn = *max_element(itL, itR); 
            return lower_bound(itR, nums.end(), maxn) - upper_bound(nums.begin(), itL, minn);
        }   
    };

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值