LeetCode第374场周赛
2951. 找出峰值 简单
分析:
枚举即可。不过要注意第一个和最后一个元素不算峰值。
代码:
C++代码:
class Solution {
public:
vector<int> findPeaks(vector<int>& mountain) {
int n=mountain.size() - 1;
vector<int> ans;
for(int i=1;i<n;i++){
if(mountain[i]>mountain[i-1] && mountain[i]>mountain[i+1]) ans.push_back(i);
}
return ans;
}
};
python代码:
class Solution:
def findPeaks(self, mountain: List[int]) -> List[int]:
ans = []
for i in range(1,len(mountain)-1):
if mountain[i]>mountain[i-1] and mountain[i]>mountain[i+1]:
ans.append(i)
return ans
时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)
2952. 需要添加的硬币的最小数量 中等
分析:
题目的目标:选取硬币种类最少的情况,硬币的各个组合和能表示1~target中的任意一个面值(包含边界)。
定义 s
,表示当前的硬币能表示
[
0
,
s
−
1
]
[0, s-1]
[0,s−1]中的任意一个面值。此时面对下一个硬币 x
。将其添加进当前硬币序列中,一定选择该硬币的情况下,能表示的范围为
[
x
,
s
+
x
−
1
]
[x, s+x-1]
[x,s+x−1]。对于x能不能直接添加进来,有两种情况:
-
x
<
=
s
x<=s
x<=s :此时大致情况如下图所示,即
[
0
,
s
−
1
]
[0, s-1]
[0,s−1]与
[
x
,
s
+
x
−
1
]
[x, s+x-1]
[x,s+x−1]连接,或者二者存在交集。因此能将这两个区间直接结合,得到
[
0
,
s
+
x
+
1
]
[0, s+x+1]
[0,s+x+1]。
-
x
>
s
x>s
x>s:此时大致情况如下图,即
[
0
,
s
−
1
]
[0, s-1]
[0,s−1]与
[
x
,
s
+
x
−
1
]
[x, s+x-1]
[x,s+x−1]中间存在一定的空白区域,
[
s
,
x
−
1
]
[s, x-1]
[s,x−1],如果直接将该硬币加入则会有一段不能表示。此时需要手动添加一个硬币,贪心思路,直接添加一个面值为s的硬币,将硬币能表示的范围扩大到
[
0
,
2
s
−
1
]
[0, 2s-1]
[0,2s−1](与第一种情况一致,相当于
x
=
s
x=s
x=s)。然后再判断x能否直接添加。
为实现最少得硬币添加数,我们对数组先进行升序排序。
如果不排序,可能会出现多添加硬币的情况,即:当前出现了情况二,但其实后面有能直接添加的较小硬币。
先将面值小的硬币添加进去,当出现情况二时只能添加硬币解决,因为没有更小的面值的硬币了。
代码:
C++代码:
class Solution {
public:
int minimumAddedCoins(vector<int>& coins, int target) {
sort(coins.begin(), coins.end());
int s=1,i=0, ans=0;
while(s<=target){
if(i<coins.size() && coins[i]<=s){
s+=coins[i];
i++;
}else{
s+=s;
ans++;
}
}
return ans;
}
};
python代码:
class Solution:
def minimumAddedCoins(self, coins: List[int], target: int) -> int:
s=1
ans=0
i=0
coins.sort()
while s <= target:
if i<len(coins) and coins[i] <= s:
s+=coins[i]
i+=1
else:
s+=s
ans+=1
return ans
时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)
空间复杂度: O ( 1 ) O(1) O(1)
2953. 统计完全子字符串 中等
分析:
数据比较大,直接枚举所有子串,然后判断很容易超时。注意到,题目条件: “相邻字符在字母表中的顺序 至多 相差 2 ”,可以利用该条件,分割得到多个满足要求的子串。
分割出来的子串中,可能包含多个满足要求的子串:aaaa
、k=3
,此时有两个子串满足要求,因此我们对于分割下来的子串要再进行滑动窗口的分割:
我们可以枚举 m(1~26) 个字符,此时满足要求的具有m个不同字符的子串长度为 k ∗ m k*m k∗m。采用滑动窗口的方式,不断地从头开始往后移动。采用一维的计数数组来进行计数,判断是否满足要求。
代码:
C++代码:
class Solution {
public:
int findString(string s, int k){
int ans=0, n=s.length();
for(int m=1;m<=26&&k*m<=n;m++){
int cnt[26]{}; // 计数数组,一维。{} 的作用是将数组的每个值均初始化为0
function<void()> check = [&](){
for(int i=0;i<26;i++){
if(cnt[i] && cnt[i]!=k) return ;// 如果值为0,则没有该字符。如果值为k则满足要求,如果值不为k,则说明该子串中该字符出现的次数不符合要求。
}
ans++;
};
for(int i=0;i<n;i++){
cnt[s[i] - 'a']++;
int j=i+1-k*m; // j~i,表示的是长度为k*m的子串,j为起始点。j<0:说明当前字符串不够长
if(j>=0){
check();
cnt[s[j] - 'a']--; // 要枚举下一个长度为k*m的子串,去掉起点,从后面加上一个字符。
}
}
}
return ans;
}
int countCompleteSubstrings(string word, int k) {
int n=word.length(), ans=0;
for(int i=0;i<n;){
int j=i;i++;
while(i<n && abs(int(word[i]) - int(word[i-1]))<=2) i++;
ans += findString(word.substr(j,i-j), k); // 将满足要求的各个子串分割下来,用于进一步判断
}
return ans;
}
};
python代码::
class Solution:
def findSubstrings(self, s: str, k: int) -> int:
ans = 0
for m in range(1,27):
if k*m > len(s):
break
cnt = Counter()
def check():
for _,v in cnt.items():
if v!=0 and v!=k:
return False
return True
for i in range(len(s)):
cnt[s[i]]+=1
j = i+1-k*m
if j >= 0:
if check():
ans+=1
cnt[s[j]]-=1
return ans
def countCompleteSubstrings(self, word: str, k: int) -> int:
n=len(word)
i=0
ans=0
while i<n:
j=i
i+=1
while i<n and abs(ord(word[i]) - ord(word[i - 1]))<=2:
i+=1
ans += self.findSubstrings(word[j:i], k)
return ans
时间复杂度: O ( n ∗ 26 ∗ 26 ) O(n * 26 *26) O(n∗26∗26)
空间复杂度:
O
(
25
)
O(25)
O(25),只创建了计数数组与一些变量