---
# System prepended metadata

title: Weekly Contest 356
tags: [Weekly Contest]

---

###### 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 &lt;= n == hours.length &lt;= 50</code></li>
<li><code>0 &lt;= hours[i], target &lt;= 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 &lt;= nums.length &lt;= 1000</code></li>
<li><code>1 &lt;= nums[i] &lt;= 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 &lt;= a.length, b.length, c.length &lt;= 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 &lt;= int(low) &lt;= int(high) &lt; 10<sup>100</sup></code></li>
<li><code>1 &lt;= low.length, high.length &lt;= 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;      
    }
};
```

