3095.或值至少K的最短子数组I
给你一个 非负 整数数组 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 <= 50
0 <= nums[i] <= 50
0 <= k < 64
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int minimumSubarrayLength(vector<int>& nums, int k) {
int ans=100;
int n=nums.size();
for(int i=0; i<n;i++){
int res=0;
for(int j=i;j<n;j++){
res=(res|nums[j]);//或
cout<<res<<endl;
if(res>=k){
ans=min(ans,j-i+1);
}
}
}
if(ans==100){
ans=-1;
}
return ans;
}
int main(){
vector<int> nums={2,1,8};
cout<<minimumSubarrayLength(nums,10)<<endl;
return 0;
}
3096.得到更多分数的最少关卡数目
给你一个长度为 n
的二进制数组 possible
。
莉叩酱和冬坂五百里正在玩一个有 n
个关卡的游戏,游戏中有一些关卡是 困难 模式,其他的关卡是 简单 模式。如果 possible[i] == 0
,那么第 i
个关卡是 困难 模式。一个玩家通过一个简单模式的关卡可以获得 1
分,通过困难模式的关卡将失去 1
分。
游戏的一开始,莉叩酱将从第 0
级开始 按顺序 完成一些关卡,然后冬坂五百里会完成剩下的所有关卡。
假设两名玩家都采取最优策略,目的是 最大化 自己的得分,莉叩酱想知道自己 最少 需要完成多少个关卡,才能获得比冬坂五百里更多的分数。
请你返回莉叩酱获得比冬坂五百里更多的分数所需要完成的 最少 关卡数目,如果 无法 达成,那么返回 -1
。
注意,每个玩家都至少需要完成 1
个关卡。
示例 1:
输入:possible = [1,0,1,0]
输出:1
解释:
我们来看一下莉叩酱可以完成的关卡数目:
- 如果莉叩酱只完成关卡 0 ,冬坂五百里完成剩下的所有关卡,那么莉叩酱获得 1 分,冬坂五百里获得 -1 + 1 - 1 = -1 分。
- 如果莉叩酱完成到关卡 1 ,冬坂五百里完成剩下的所有关卡,那么莉叩酱获得 1 - 1 = 0 分,冬坂五百里获得 1 - 1 = 0 分。
- 如果莉叩酱完成到关卡 2 ,冬坂五百里完成剩下的所有关卡,那么莉叩酱获得 1 - 1 + 1 = 1 分,冬坂五百里获得 -1 分。
莉叩酱需要完成至少一个关卡获得更多的分数。
示例 2:
输入:possible = [1,1,1,1,1]
输出:3
解释:
我们来看一下莉叩酱可以完成的关卡数目:
- 如果莉叩酱只完成关卡 0 ,冬坂五百里完成剩下的所有关卡,那么莉叩酱获得 1 分,冬坂五百里获得 4 分。
- 如果莉叩酱完成到关卡 1 ,冬坂五百里完成剩下的所有关卡,那么莉叩酱获得 2 分,冬坂五百里获得 3 分。
- 如果莉叩酱完成到关卡 2 ,冬坂五百里完成剩下的所有关卡,那么莉叩酱获得 3 分,冬坂五百里获得 2 分。
- 如果莉叩酱完成到关卡 3 ,冬坂五百里完成剩下的所有关卡,那么莉叩酱获得 4 分,冬坂五百里获得 1 分。
莉叩酱需要完成至少三个关卡获得更多的分数。
示例 3:
输入:possible = [0,0]
输出:-1
解释:
两名玩家只能各完成 1 个关卡,莉叩酱完成关卡 0 得到 -1 分,冬坂五百里完成关卡 1 得到 -1 分。两名玩家得分相同,所以莉叩酱无法得到更多分数。
提示:
2 <= n == possible.length <= 105
possible[i]
要么是0
要么是1
。
#include<iostream>
#include<vector>
#include <numeric>
using namespace std;
int minimumLevels(vector<int>& possible) {
//pre>s-pre
//pre*2>s
int n=possible.size();
for(int i=0;i<n;i++){
if(possible[i]==0) possible[i]=-1;
}
int s=accumulate(possible.begin(), possible.end(),0);
int cnt=0;int pre=0;
for(int i=0;i<n-1;i++){
pre+=possible[i];
cnt++;
if(pre*2>s){
return cnt;
}
}
return -1;
}
int main(){
vector<int> possible={1,0,1,0};
cout<<minimumLevels(possible)<<endl;
return 0;
}
3097.或值至少为K的最短子数组II
这个题和第一题一样,只有数字规模不一样
提示:
1 <= nums.length <= 2 * 105
0 <= nums[i] <= 109
0 <= k <= 109
#include<iostream>
#include<vector>
#include <climits>
using namespace std;
// int minimumSubarrayLength(vector<int>& nums, int k) {
// int ans=INT_MAX;
// vector<pair<int,int> >ors; //(保存右端点为i的子数组or,该子数组左端点的最大值
// for(int i=0;i<nums.size();i++) {
// ors.emplace_back(0,i);
// int j=0;
// for(auto &p :ors){
// auto &[or_,left]=p;
// or_=or_|nums[i];
// if(or_>=k){
// ans=min(ans,i-left+1);
// }
// if(ors[j].first==or_){
// ors[j].second=left;
// } else{
// ors[j++]=p;
// }
// }
// ors.resize(j+1);
// }
// return ans ==INT_MAX?-1:ans;
// }
int minimumSubarrayLength(vector<int>& nums, int k) {
if(k==0) return 1;
int ans=INT_MAX,n=nums.size(),cur=0;
vector<int>mem(32); //用于累计窗口中各数位有多少个1
//为什么是32呢,是因为0 <= nums[i] <= 10^9 也就是不大于2^32,最多32个1这样子
int l=0,r=0;
while(l<=r&&r<n){
for(int j=0;j<32;j++){
if((nums[r]>>j)&1){ //右移除2
mem[j]++;
if(((cur>>j)&1)==0) //原来没有置1,才置1.注意不要重复
cur+=(1<<j);
}
}
r++;
//在窗口和>=k时,移动左指针到窗口和<k,或者
//右指针已经移动到最右端时,移动左指针到最右端
while((cur>=k||r==n)&&l<r){
if(cur>=k) ans=min(ans,r-l);
for(int j=0;j<32;j++){
if((nums[l]>>j)&1){
mem[j]--;
if(mem[j]==0) cur=cur-(1<<j);
}
}
l++;
}
}
return ans==INT_MAX ? -1 : ans;
}
int main(){
vector<int> nums={2,1,8};
cout<<minimumSubarrayLength(nums,10)<<endl;
return 0;
}
按照滑动窗口写,时间复杂度为O(n),空间O(1),而且感觉更好理解。
C/C++ 左移<<, 右移>>作用_c++ <<(左移)-CSDN博客
我们都知道,或运算是运算的数字序列越多肯定越好,毕竟1|0=1,1|1=1,只有0|0=0.
但是我们在滑动窗口计算两个数或运算之后1的个数时,不能把同样位置的1重复加才是
if(((cur>>j)&1)==0) //原来没有置1,才置1.注意不要重复
cur+=(1<<j);
300.最长递增子序列
给你一个整数数组 nums
,找到其中最长严格递增子序列的长度。
子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7]
是数组 [0,3,1,6,2,2,7]
的
子序列
。
示例 1:
输入:nums = [10,9,2,5,3,7,101,18] 输出:4 解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
示例 2:
输入:nums = [0,1,0,3,2,3] 输出:4
示例 3:
输入:nums = [7,7,7,7,7,7,7] 输出:1
提示:
1 <= nums.length <= 2500
-104 <= nums[i] <= 104
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int lengthOfLIS(vector<int>& nums) {
int n=nums.size();
if(n==0) return 0;
vector<int> dp(n,0);
for(int i=0; i<n; i++){
dp[i]=1;
for(int j=0;j<i;j++){
if(nums[j]<nums[i]){
dp[i]=max(dp[i],dp[j]+1);
}
}
}
return *max_element(dp.begin(),dp.end());
}
int main(){
vector<int>nums={0,1,0,3,2,3};
cout<<lengthOfLIS(nums)<<endl;
return 0;
}
要想写最后一题,可以先看一下上面这个题。
dp[i]=max(dp[i],dp[j]+1) ,nums[i]>nums[j]
时间复杂度O(n^2).