第 315 场周赛 - 力扣(LeetCode)
https://leetcode.cn/contest/weekly-contest-315/
6204. 与对应负数同时存在的最大正整数-Easy
题目描述:
给你一个 不包含 任何零的整数数组 nums ,找出自身与对应的负数都在数组中存在的最大正整数 k 。
返回正整数 k ,如果不存在这样的整数,返回 -1 。
题目解析:
直接两个嵌套的for循环进行查找,如果存在一个数的正负数都在数组中那么将该数存起来,并且在查找中更新最大值即可,代码如下:
class Solution {
public:
int findMaxK(vector<int>& nums) {
int res = -1;
for(int i = 0 ; i<nums.size() ; i++){
for(int j = 0 ; j<nums.size() ; j++){
if(nums[j]==-nums[i]&&j!=i){
res = max(res,abs(nums[j]));
}
}
}
return res;
}
};
执行用时:344 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗:19.1 MB, 在所有 C++ 提交中击败了100.00%的用户
6205. 反转之后不同整数的数目-Medium
题目描述:
给你一个由 正 整数组成的数组 nums 。
你必须取出数组中的每个整数,反转其中每个数位,并将反转后得到的数字添加到数组的末尾。这一操作只针对 nums 中原有的整数执行。
返回结果数组中 不同 整数的数目。
题目解析:
首先通过一个函数计算每个数的反转数,将其存入数组中,然后对数组进行排序,遍历数组寻找数组有几个不同的值即可,其实感觉可以用unordered_set来解决这个问题,这里就不细说了,代码如下:
class Solution {
public:
int cal(int num){
int res = 0;
while(num!=0){
res = res*10+num%10;
num/=10;
}
return res;
}
int countDistinctIntegers(vector<int>& nums) {
int len = nums.size();
for(int i = 0 ; i<len ; i++){
int temp = cal(nums[i]);
nums.push_back(temp);
}
sort(nums.begin(),nums.end());
int res = 1;
int temp = nums[0];
for(int i = 1 ; i<nums.size() ; i++){
if(nums[i]!=temp){
temp = nums[i];
res++;
}
}
return res;
}
};
执行用时:172 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗:57.7 MB, 在所有 C++ 提交中击败了100.00%的用户
6219. 反转之后的数字和-Medium
题目描述:
给你一个 非负 整数 num 。如果存在某个 非负 整数 k 满足 k + reverse(k) = num ,则返回 true ;否则,返回 false 。
reverse(k) 表示 k 反转每个数位后得到的数字。
题目解析:
暴力枚举,挺简单的,通过上一道题的计算反转数字的函数,然后进行枚举即可,代码如下:
class Solution {
public:
int cal(int num){
int res = 0;
while(num!=0){
res = res*10+num%10;
num/=10;
}
return res;
}
bool sumOfNumberAndReverse(int num) {
for(int i = 0 ; i<=num ; i++){
if(i+cal(i)==num)return true;
}
return false;
}
};
执行用时:80 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗:5.9 MB, 在所有 C++ 提交中击败了100.00%的用户
6207. 统计定界子数组的数目-Hard
题目描述:
给你一个整数数组 nums 和两个整数 minK 以及 maxK 。
nums 的定界子数组是满足下述条件的一个子数组:
子数组中的 最小值 等于 minK 。
子数组中的 最大值 等于 maxK 。
返回定界子数组的数目。
子数组是数组中的一个连续部分。
题目解析:
有点子小难,主要是有点难想,前面三道题一共花了差不多二十多分钟,然后最后一道题发呆愣了一个小时没做出来,我一开始的想法是通过单调栈的原理来找,即我先找到一个minK-maxK或者maxK-minK的区间,然后我在这个区间上进行左右扩散,看最远能扩到多少,比如能够扩n个数,那么这个区间能够构成的子数组就是,1+2+...+n-1,但是这个做法就很难去做去重,所以我将近一个小时都在考虑怎么去重,代码如下(虽然是错的,但是个经验,该说不说,我还挺能写废话代码):
class Solution {
public:
long long countSubarrays(vector<int>& nums, int minK, int maxK) {
vector<int> num;
vector<int> pos;
stack<int> stk;
long long ans = 0;
for(int i = 0 ; i<nums.size() ; i++){
if(stk.empty()&&(nums[i]==minK||nums[i]==maxK))stk.push(i);
if(!stk.empty()&&(nums[i]==minK&&nums[stk.top()]==maxK)){
int res = 1;
int pos = 0;
for(pos = stk.top()-1 ; pos>=0 ; pos--){
if(nums[pos]<=maxK&&nums[pos]>=minK)res++;
else break;
}
for(pos = i+1 ; pos<nums.size() ; pos++){
if(nums[pos]<=maxK&&nums[pos]>=minK)res++;
else break;
}
num.push_back(res);
stk.pop();
i = pos-1;
}
if(!stk.empty()&&(nums[i]==maxK&&nums[stk.top()]==minK)){
int res = 1;
int pos = 0;
for(pos = stk.top()-1 ; pos>=0 ; pos--){
if(nums[pos]<=maxK&&nums[pos]>=minK)res++;
else break;
}
for(pos = i+1 ; pos<nums.size() ; pos++){
if(nums[pos]<=maxK&&nums[pos]>=minK)res++;
else break;
}
num.push_back(res);
stk.pop();
i = pos-1;
}
}
stack<int> stk_c;
for(int i = 0 ; i<nums.size() ; i++){
if(stk_c.empty()&&(nums[i]==minK||nums[i]==maxK))stk_c.push(i);
if(!stk_c.empty()&&(nums[i]==minK&&nums[stk_c.top()]==maxK)){
ans++;
stk_c.pop();
}
if(!stk_c.empty()&&(nums[i]==maxK&&nums[stk_c.top()]==minK)){
ans++;
stk_c.pop();
}
}
for(int i = 0 ; i<num.size() ; i++){
for(int data = num[i]-1 ; data>0 ; data--){
ans += data;
}
}
return ans;
}
};
然后看了一下题解过后,恍然大悟,是真的聪明,题目是怎么考虑的呢,首先我在遍历的过程中记录最近一次出现的minK和maxK的位置,并且记录最近的一个不在minK和maxK范围内的位置,如果这个数可以作为子区间的右端点,那么这个数的左端点有多少选择呢,minK和maxK位置的最小值减去最近的超出范围的数据位置,如果小于0的话,说明以该数为右端点不能构成符合条件的子数组,则为0即可,代码如下:
class Solution {
public:
long long countSubarrays(vector<int>& nums, int minK, int maxK) {
long long res = 0;
int minI = -1;
int maxI = -1;
int idx = -1;
for(int i = 0 ; i<nums.size() ; i++){
if(nums[i]==minK)minI = i;
if(nums[i]==maxK)maxI = i;
if(nums[i]<minK||nums[i]>maxK)idx = i;
res += max(min(minI,maxI)-idx,0);
}
return res;
}
};
执行用时:68 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗:68.7 MB, 在所有 C++ 提交中击败了100.00%的用户
感觉就是这种题可以通过从后往前去考虑,而不是一直想着正向怎么去求解,我只需要计算每个数作为右端点能够产生几个子数组,那么所有数对应的结果加起来就是我要求的结果。算法的魅力~!