LeetCode每日一题
275. H 指数 II
给你一个整数数组
citations
,其中citations[i]
表示研究者的第i
篇论文被引用的次数,citations
已经按照 升序排列 。计算并返回该研究者的 h 指数。h 指数的定义:h 代表“高引用次数”(high citations),一名科研人员的
h
指数是指他(她)的 (n
篇论文中)总共有h
篇论文分别被引用了至少h
次。请你设计并实现对数时间复杂度的算法解决此问题。
#解题思路和优化思路
这道题和上周末的那道H指数很像 但是他用的是升序数组 无形之中给我们提示 告诉我们需要使用二分法 而最后的要求也明确表示需要用对数时间复杂度的算法结构来解题 所以这道题就是二分套二分 通过二分来加速数组的遍历 加速寻找合适的最大的最小下标 满足大于nums[k]的个数>=k
#Coding
class Solution {
bool check(int k,vector<int>& citations)
{
int left=0,right=citations.size()-1;
while(left<right)
{
int mid=(left+right-1)/2;
if(citations[mid]>=k) right=mid;
else left=mid+1;
}
return citations.size()-left>=k;
}
public:
int hIndex(vector<int>& citations) {
int n=citations.size();
int left=citations[0],right=citations[n-1];
while(left<right)
{
int mid=(left+right+1)/2;
if(check(mid,citations)) left=mid;
else right=mid-1;
}
return min(left,n);
}
};
LeetCode周赛(116双周赛)
2913. 子数组不同元素数目的平方和 I
给你一个下标从 0 开始的整数数组
nums
。定义
nums
一个子数组的 不同计数 值如下:
- 令
nums[i..j]
表示nums
中所有下标在i
到j
范围内的元素构成的子数组(满足0 <= i <= j < nums.length
),那么我们称子数组nums[i..j]
中不同值的数目为nums[i..j]
的不同计数。请你返回
nums
中所有子数组的 不同计数 的 平方 和。由于答案可能会很大,请你将它对
109 + 7
取余 后返回。子数组指的是一个数组里面一段连续 非空 的元素序列。
#解题思路和优化思路
这道题是T1级别的题目 所以直接暴力代码过 暴力的遍历数组 同时从当前遍历下标开始遍历数组 统计不同的数字个数并放入哈希表中 最后令 res 加上 哈希表的size就是答案
#Coding
class Solution {
public:
int sumCounts(vector<int>& nums) {
int res=0;
const int mod=1e9+7;
for(int i=0;i<nums.size();++i)
{
unordered_set<int> uset;
uset.clear();
for(int j=i;j<nums.size();++j)
{
uset.insert(nums[j]);
int size=uset.size();
res=(res+(size*size)%mod)%mod;
}
}
return res;
}
};
2914. 使二进制字符串变美丽的最少修改次数
给你一个长度为偶数下标从 0 开始的二进制字符串
s
。如果可以将一个字符串分割成一个或者更多满足以下条件的子字符串,那么我们称这个字符串是 美丽的 :
- 每个子字符串的长度都是 偶数 。
- 每个子字符串都 只 包含
1
或 只 包含0
。你可以将
s
中任一字符改成0
或者1
。请你返回让字符串
s
美丽的 最少 字符修改次数。
#解题思路和优化思路
这道题更像是脑筋急转弯的问题 由于s的长度是偶数 并且每一个子数组串也是偶数 所以他一定是可以被分解完毕而不会剩下余数的 当前问题知道之后 我们就可以设定贪心策略 即 每两个为一组 如果两个不一样 就令 res++ 因为他的子数组串必须是偶数个 即 2 4 6 当子数组的数字个数越多 他需要相同的修改数字就需要更多 所以当每一个数组的数字个数都是2个的时候 就是最优解
#Coding
class Solution {
public:
int minChanges(string s) {
int res=0;
for(int i=0;i<s.size();i+=2)
{
if(s[i]!=s[i+1]) res++;
}
return res;
}
};
2915. 和为目标值的最长子序列的长度
给你一个下标从 0 开始的整数数组
nums
和一个整数target
。返回和为
target
的nums
子序列中,子序列 长度的最大值 。如果不存在和为target
的子序列,返回-1
。子序列 指的是从原数组中删除一些或者不删除任何元素后,剩余元素保持原来的顺序构成的数组。
#解题思路和优化思路
0-1背包问题 很简单的一道题 背包的容量是 target 现在又n个数字 返回可以刚刚好填满背包的最多物品个数 问题转化到这里 就很简单了 套用01背包的板子即可解决问题
#Coding
class Solution {
public:
int lengthOfLongestSubsequence(vector<int>& nums, int target) {
vector<int> dp(target+1,INT_MIN);
dp[0]=0;
int s=0;
for(int i=0;i<nums.size();++i)
{
s=min(s+nums[i],target);
for(int j=s;j>=nums[i];--j)
{
dp[j]=max(dp[j],dp[j-nums[i]]+1);
}
}
return dp[target]>0?dp[target]:-1;
}
};
2916. 子数组不同元素数目的平方和 II
给你一个下标从 0 开始的整数数组
nums
。定义
nums
一个子数组的 不同计数 值如下:
- 令
nums[i..j]
表示nums
中所有下标在i
到j
范围内的元素构成的子数组(满足0 <= i <= j < nums.length
),那么我们称子数组nums[i..j]
中不同值的数目为nums[i..j]
的不同计数。请你返回
nums
中所有子数组的 不同计数 的 平方 和。由于答案可能会很大,请你将它对
109 + 7
取余 后返回。子数组指的是一个数组里面一段连续 非空 的元素序列。
#解题思路和优化思路
和T1 是一样的题目 但是时间复杂度需要降低到O(N*logN) 才能实现AC 这里我们引入一个数据结构线段树来优化这道题的时间复杂度
#Coding
洛谷算法1-2
P1923 【深基9.例4】求第 k 小的数
题目描述
输入 n(1< n < 50000001≤n<5000000 且 n 为奇数)个数字
(
),输出这些数字的第 k 小的数。最小的数是第 0 小。
请尽量不要使用
nth_element
来写本题,因为本题的重点在于练习分治算法
#解题思路和优化思路
这道题我只会使用堆来加速 但是这道题要求的时间复杂度是 O(N) 才能完全AC 所以我只得了60分 这道题通过查看题解 发现需要用到的知识点通过 快排 的使用来加速二分的优化思路 快排的方式就不多叙述了 只讲一下如何利用快排加速算法 利用快排可以将数组分成三个部分 即 小于基准数的 大于基准数的 以及等于基准数的 如果基准数下标小于等于 k 则去大于基准数的地方继续寻找 反之就去小于基准数的地方找 即通过这种方法 不需要遍历整个数组 就可以快速的得到答案 同时学到了快读 对以后的写代码有很大的帮助
#Coding
#include<bits/stdc++.h>
using namespace std;
vector<long long> nums;
inline int read()
{
int flag=1,val=0;
char ch=getchar();
if(ch>'9' || ch<'0')
{
if(ch=='-') flag=-1;
ch=getchar();
}
while(ch>='0' && ch<='9')
{
val=val*10+(ch-'0');
ch=getchar();
}
return val;
}
int quilkSort(int left,int right)
{
int mid=nums[left];
while(left<right)
{
while(left<right && nums[right]>=mid)
{
right--;
}
nums[left]=nums[right];
while(left<right && nums[left]<=mid)
{
left++;
}
nums[right]=nums[left];
}
nums[left]=mid;
return left;
}
void find(int left,int right,int k)
{
int idx=quilkSort(left,right);
if(idx==k)
{
cout<<nums[idx];
exit(0);
}
else if(idx>k-1) find(left,idx-1,k);
else find(idx+1,right,k);
}
int main()
{
int n=read();
int k=read();
nums.resize(n);
for(int i=0;i<n;++i)
{
scanf("%d",&nums[i]);
}
find(0,n-1,k);
return 0;
}
P1271 【深基9.例1】选举学生会
题目描述
学校正在选举学生会成员,有 nn(n\le 999n≤999)名候选人,每名候选人编号分别从 11 到 nn,现在收集到了 mm(m \le 2000000m≤2000000)张选票,每张选票都写了一个候选人编号。现在想把这些堆积如山的选票按照投票数字从小到大排序。
#解题思路和优化思路
接下来的两道题就非常的简单 没有什么特别的套路 就是排序数组就好了 调用库函数 sort 来完成算法问题
#Coding
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,m;
cin>>n>>m;
vector<int> nums(m);
for(int i=0;i<m;++i)
{
cin>>nums[i];
}
sort(nums.begin(),nums.end());
for(int i=0;i<m;++i)
{
if(i) cout<<" ";
cout<<nums[i];
}
return 0;
}
P1177 【模板】排序
题目描述
将读入的 N 个数从小到大排序后输出。
#Coding
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin>>n;
vector<int> nums(n);
for(int i=0;i<n;++i)
{
cin>>nums[i];
}
sort(nums.begin(),nums.end());
for(int i=0;i<n;++i)
{
if(i) cout<<" ";
cout<<nums[i];
}
return 0;
}