###### tags: `Weekly Contest`
# Weekly Contest 356
## [2798. Number of Employees Who Met the Target](https://leetcode.com/problems/number-of-employees-who-met-the-target/)(<font color=#00B8A3>Easy</font>)
限制 :
<ul>
<li><code>1 <= n == hours.length <= 50</code></li>
<li><code>0 <= hours[i], target <= 10<sup>5</sup></code></li>
</ul>
### Solution
#### 時間複雜度: $O(n)$
#### 空間複雜度: $O(1)$
程式碼:
```c++=
class Solution {
public:
int numberOfEmployeesWhoMetTarget(vector<int>& hours, int target) {
int ans=0;
for(int i=0;i<hours.size();i++){
if(hours[i]>=target)
ans++;
}
return ans;
}
};
```
## [2799. Count Complete Subarrays in an Array](https://leetcode.com/problems/count-complete-subarrays-in-an-array/)(<font color=#FFC011>Medium</font>)
限制 :
<ul>
<li><code>1 <= nums.length <= 1000</code></li>
<li><code>1 <= nums[i] <= 2000</code></li>
</ul>
### Solution
暴力窮舉所有 subarray,接著用 set 統計 subarray 不同元素的數量來 check 這個 subarray 是否是 complete。
有一個小優化的部分,只要 $nums[i:j]$ 是 complete,那 $nums[i:j+1]$、$nums[i:j+2]\ ...$ 也都是 complete。所以對於每個 $i$ 只需要算出第一個 complete 的 $j$,後面的就不用額外計算。
#### 時間複雜度: $O(n^2)$
#### 空間複雜度: $O(n)$
程式碼:
```c++=
class Solution {
public:
int countCompleteSubarrays(vector<int>& nums) {
int n=nums.size();
set<int> target;
for(auto &num: nums){
target.insert(num);
}
int ans = 0;
for(int i=0;i<n;i++){
set<int> si;
for(int j=i;j<n;j++){
si.insert(nums[j]);
if(si.size() == target.size()){
ans += n-j;
break;
}
}
}
return ans;
}
};
```
## [2800. Shortest String That Contains Three Strings](https://leetcode.com/problems/shortest-string-that-contains-three-strings/)(<font color=#FFC011>Medium</font>)
限制 :
<ul>
<li><code>1 <= a.length, b.length, c.length <= 100</code></li>
<li><code>a</code>, <code>b</code>, <code>c</code> consist only of lowercase English letters.</li>
</ul>
### Solution
相當搞的一題,在細節debug上花費了非常多的時間。
核心概念是做出 merge 這個操作,merge 的意義是將 $s$ 字串與 $t$ 字串串接起來並去除重複,以下舉幾個範例:
* merge("abc", "bca") -> "abca"
* merge("abca", "aaa") -> "abcaaa"
答案一定會出現在 abc 這三個字串的所有排列 merge 之中,也就是以下6個答案:
* merge(merge(a, b), c)
* merge(merge(a, c), b)
* merge(merge(b, a), c)
* merge(merge(b, c), a)
* merge(merge(c, a), b)
* merge(merge(c, b), a)
算出六個答案之後照著題目要求選出最短且 lexicographically smallest 的字串即可。
n = max(a.size(), b.size(), c.size())
#### 時間複雜度: $O(n^2)$
#### 空間複雜度: $O(n)$
程式碼:
```c++=
class Solution {
public:
bool contain(string &a, string &b, string &c){
return a.find(b) !=string::npos&&a.find(c) !=string::npos;
}
string merge(string a, string b){
if(a.find(b) !=string::npos||b.find(a) !=string::npos)
return a.size()>b.size()?a:b;
int n = min(a.size(), b.size());
for(int i=n-1, j=0;i>=0;i--, j++){
if(a.substr(a.size()-i-1) == b.substr(0, i+1))
return a.substr(0, a.size()-i-1)+a.substr(a.size()-i-1)+b.substr(i+1);
}
return a+b;
}
static bool cmp(string &a, string &b){
if(a.size() == b.size())
return a<b;
return a.size()<b.size();
}
string minimumString(string a, string b, string c) {
vector<string> d, temp;
temp.push_back(a), temp.push_back(b), temp.push_back(c);
int cnt=6, i=0;
while(cnt--){
d.push_back(merge(merge(temp[0], temp[1]), temp[2]));
next_permutation(temp.begin(), temp.end());
}
sort(d.begin(), d.end(), cmp);
return d[0];
}
};
```
## [2801. Count Stepping Numbers in Range](https://leetcode.com/problems/count-stepping-numbers-in-range/)(<font color=#FF375F>Hard</font>)
限制 :
<ul>
<li><code>1 <= int(low) <= int(high) < 10<sup>100</sup></code></li>
<li><code>1 <= low.length, high.length <= 100</code></li>
<li><code>low</code> and <code>high</code> consist of only digits.</li>
<li><code>low</code> and <code>high</code> don't have any leading zeros.</li>
</ul>
### Solution
很搞的題\*2,debug de 了一小時多。
這是經典的 digit dp。因為直接算出 $[low, high]$ 中的 stepping number 的數量很困難,所以我們先算出 $[1, high]$ 的數量,再算出 $[1, low-1]$ 的數量,兩個相減就是 $[low, high]$ 的數量。
問題現在被簡化成如何算出 $[1, limit]$ 的數量了,要快速的算這個問題需要用到 digit dp。
令 $dp[i][j]$ 為長度為 $i$ 且最大位數為 $j$ 的 stepping number 的數量。
顯而易見的,$dp[0][0:9] := 1$,因為 1~9 都是 stepping number,我們可以透過當前位數的答案去計算下一位數有幾個 stepping number,dp式:
$$ dp[i][j] = dp[i-1][j-1] + dp[i-1][j+1] $$
以 $dp[1][1]$ 舉例的話,正確答案是 12,10,阿這些答案又是根據上一位數的0跟2個別在最高位接上1所算出來的,所以 $dp[1][1] = dp[0][0]+dp[0][2]$。
m = 10
#### 時間複雜度: $O(n*m)$
#### 空間複雜度: $O(n*m)$
程式碼:
```c++=
class Solution {
public:
const int MOD = 1e9+7;
void dfs(int idx, int sign, int &ans, string &s, vector<vector<int> > &dp){
if(idx == s.size()-1)
return ;
if(s[idx+1]>s[idx]+sign)
return ;
else if(s[idx+1]<s[idx]+sign){
if(s[idx]+sign-'0'>=0&&s[idx]+sign-'0'<10)
ans = (ans - dp[s.size()-idx-2][s[idx]+sign-'0'] + MOD)%MOD;
}
else {
dfs(idx+1, 1, ans, s, dp);
dfs(idx+1, -1, ans, s, dp);
}
}
int countNumber(string &s){
if(s.size()==1)
return s[0]-'0';
int n=s.size();
vector<vector<int> > dp(n, vector<int>(10));
for(int i=0;i<=9;i++)
dp[0][i] = 1;
int ans = 9;
for(int i=1;i<n;i++){
for(int j=0;j<10;j++){
if(j-1>=0)
dp[i][j] = (dp[i][j]+dp[i-1][j-1])%MOD;
if(j+1<10)
dp[i][j] = (dp[i][j]+dp[i-1][j+1])%MOD;
if(j !=0)
ans = (ans + dp[i][j])%MOD;
}
}
for(int i=s[0]-'0'+1;i<10;i++)
ans = (ans - dp[n-1][i] + MOD)%MOD;
dfs(0, 1, ans, s, dp);
dfs(0, -1, ans, s, dp);
return ans;
}
int countSteppingNumbers(string low, string high) {
low[low.size()-1]--;
for(int i=low.size()-1;i>=0;i--){
if(low[i]<'0'){
low[i-1]--;
low[i]+=10;
}
else {
break;
}
}
return (countNumber(high)-countNumber(low) + MOD)%MOD;
}
};
```