LeetCode Weekly Contest 182

5368. 找出數組中的幸運數

在整數數組中,如果一個整數的出現頻次和它的數值大小相等,我們就稱這個整數爲「幸運數」。

給你一個整數數組 arr,請你從中找出並返回一個幸運數。

如果數組中存在多個幸運數,只需返回 最大 的那個。
如果數組中不含幸運數,則返回 -1 。

示例 1:

輸入:arr = [2,2,3,4]
輸出:2
解釋:數組中唯一的幸運數是 2 ,因爲數值 2 的出現頻次也是 2 。
示例 2:

輸入:arr = [1,2,2,3,3,3]
輸出:3
解釋:1、2 以及 3 都是幸運數,只需要返回其中最大的 3 。
示例 3:

輸入:arr = [2,2,2,3,3]
輸出:-1
解釋:數組中不存在幸運數。
示例 4:

輸入:arr = [5]
輸出:-1
示例 5:

輸入:arr = [7,7,7,7,7,7,7]
輸出:7

提示:

1 <= arr.length <= 500
1 <= arr[i] <= 500

代碼

class Solution {
    public int findLucky(int[] arr) {
        Arrays.sort(arr);
        int cnt = 0, i = 0, n = arr.length, pre = -1, num = 0;
        for (i=n-1; i>=0; --i) {
            num = arr[i];
            if (num == pre) {
                ++cnt;
            } else {
                if (cnt == pre) {
                    return pre;
                }
                pre = num;
                cnt = 1;
            }
        }
        if (cnt == pre) {
            return pre;
        } else {
            return -1;
        }
    }
}

5369. 統計作戰單位數

n 名士兵站成一排。每個士兵都有一個 獨一無二 的評分 rating 。

每 3 個士兵可以組成一個作戰單位,分組規則如下:

從隊伍中選出下標分別爲 i、j、k 的 3 名士兵,他們的評分分別爲 rating[i]、rating[j]、rating[k]
作戰單位需滿足: rating[i] < rating[j] < rating[k] 或者 rating[i] > rating[j] > rating[k] ,其中 0 <= i < j < k < n
請你返回按上述條件可以組建的作戰單位數量。每個士兵都可以是多個作戰單位的一部分。

示例 1:

輸入:rating = [2,5,3,4,1]
輸出:3
解釋:我們可以組建三個作戰單位 (2,3,4)、(5,4,1)、(5,3,1) 。
示例 2:

輸入:rating = [2,1,3]
輸出:0
解釋:根據題目條件,我們無法組建作戰單位。
示例 3:

輸入:rating = [1,2,3,4]
輸出:4

提示:

n == rating.length
1 <= n <= 200
1 <= rating[i] <= 10^5

代碼

class Solution {
    public int numTeams(int[] rating) {
        int n = rating.length, i = 0, j = 0, k = 0, cnt = 0;
        for (i=0; i<n; ++i) {
            for (j=i+1; j<n; ++j) {
                for (k=j+1; k<n; ++k) {
                    if (rating[i] < rating[j] && rating[j] < rating[k]) {
                        ++cnt;
                    } else if (rating[i] > rating[j] && rating[j] > rating[k]) {
                        ++cnt;
                    }
                }
            }
        }
        return cnt;
    }
}

5370. 設計地鐵系統

請你實現一個類 UndergroundSystem ,它支持以下 3 種方法:

  1. checkIn(int id, string stationName, int t)

編號爲 id 的乘客在 t 時刻進入地鐵站 stationName 。
一個乘客在同一時間只能在一個地鐵站進入或者離開。
2. checkOut(int id, string stationName, int t)

編號爲 id 的乘客在 t 時刻離開地鐵站 stationName 。
3. getAverageTime(string startStation, string endStation)

返回從地鐵站 startStation 到地鐵站 endStation 的平均花費時間。
平均時間計算的行程包括當前爲止所有從 startStation 直接到達 endStation 的行程。
調用 getAverageTime 時,詢問的路線至少包含一趟行程。
你可以假設所有對 checkIn 和 checkOut 的調用都是符合邏輯的。也就是說,如果一個顧客在 t1 時刻到達某個地鐵站,那麼他離開的時間 t2 一定滿足 t2 > t1 。所有的事件都按時間順序給出。

示例:

輸入:
[“UndergroundSystem”,“checkIn”,“checkIn”,“checkIn”,“checkOut”,“checkOut”,“checkOut”,“getAverageTime”,“getAverageTime”,“checkIn”,“getAverageTime”,“checkOut”,“getAverageTime”]
[[],[45,“Leyton”,3],[32,“Paradise”,8],[27,“Leyton”,10],[45,“Waterloo”,15],[27,“Waterloo”,20],[32,“Cambridge”,22],[“Paradise”,“Cambridge”],[“Leyton”,“Waterloo”],[10,“Leyton”,24],[“Leyton”,“Waterloo”],[10,“Waterloo”,38],[“Leyton”,“Waterloo”]]

輸出:
[null,null,null,null,null,null,null,14.0,11.0,null,11.0,null,12.0]

解釋:

UndergroundSystem undergroundSystem = new UndergroundSystem();
undergroundSystem.checkIn(45, "Leyton", 3);
undergroundSystem.checkIn(32, "Paradise", 8);
undergroundSystem.checkIn(27, "Leyton", 10);
undergroundSystem.checkOut(45, "Waterloo", 15);
undergroundSystem.checkOut(27, "Waterloo", 20);
undergroundSystem.checkOut(32, "Cambridge", 22);
undergroundSystem.getAverageTime("Paradise", "Cambridge");       // 返回 14.0。從 "Paradise"(時刻 8)到 "Cambridge"(時刻 22)的行程只有一趟
undergroundSystem.getAverageTime("Leyton", "Waterloo");          // 返回 11.0。總共有 2 躺從 "Leyton" 到 "Waterloo" 的行程,編號爲 id=45 的乘客出發於 time=3 到達於 time=15,編號爲 id=27 的乘客於 time=10 出發於 time=20 到達。所以平均時間爲 ( (15-3) + (20-10) ) / 2 = 11.0
undergroundSystem.checkIn(10, "Leyton", 24);
undergroundSystem.getAverageTime("Leyton", "Waterloo");          // 返回 11.0
undergroundSystem.checkOut(10, "Waterloo", 38);
undergroundSystem.getAverageTime("Leyton", "Waterloo");          // 返回 12.0

提示:

總共最多有 20000 次操作。
1 <= id, t <= 10^6
所有的字符串包含大寫字母,小寫字母和數字。
1 <= stationName.length <= 10
與標準答案誤差在 10^-5 以內的結果都視爲正確結果。

思路

用兩個map,一個保存上一次用戶進站信息,和當前出站用戶匹配;另一個保存當前統計到的兩個車站中的(總時間,次數)對,最後統一計算涉及到double類型計算的求平均數操作只在需要計算平均數的時候做一次。

代碼

class UndergroundSystem {
    private class CheckIn {
        public String station;
        public int time;
        
        public CheckIn(String s, int t) {
            station = s;
            time = t;
        }
    }
    
    private class Average {
        public long sum;
        public int time;
        
        public Average(long s, int t) {
            sum = s;
            time = t;
        }
        
        public double doAverage() {
            return ((double) sum) / ((double) time);
        }
        
        public void addPath(int cost) {
            ++time;
            sum += (long)cost;
        }
    }
    
    private HashMap<Integer, CheckIn> checkIns = new HashMap<>();
    private HashMap<String, HashMap<String, Average>> paths = new HashMap<>(); 

    public UndergroundSystem() {

    }
    
    public void checkIn(int id, String stationName, int t) {
        checkIns.put(id, new CheckIn(stationName, t));
    }
    
    public void checkOut(int id, String stationName, int t) {
        CheckIn ci = checkIns.get(id);
        String bs = ci.station;
        int bt = ci.time;
        if (paths.containsKey(bs) && paths.get(bs).containsKey(stationName)) {
            paths.get(bs).get(stationName).addPath(t - bt);
            return;
        }
        if (!paths.containsKey(bs)) {
            paths.put(bs, new HashMap<String, Average>());
        }
        paths.get(bs).put(stationName, new Average((long)(t-bt), 1));
    }
    
    public double getAverageTime(String startStation, String endStation) {
        return paths.get(startStation).get(endStation).doAverage();
    }
}

/**
 * Your UndergroundSystem object will be instantiated and called as such:
 * UndergroundSystem obj = new UndergroundSystem();
 * obj.checkIn(id,stationName,t);
 * obj.checkOut(id,stationName,t);
 * double param_3 = obj.getAverageTime(startStation,endStation);
 */

5371. 找到所有好字符串

給你兩個長度爲 n 的字符串 s1 和 s2 ,以及一個字符串 evil 。請你返回 好字符串 的數目。

好字符串 的定義爲:它的長度爲 n ,字典序大於等於 s1 ,字典序小於等於 s2 ,且不包含 evil 爲子字符串。

由於答案可能很大,請你返回答案對 10^9 + 7 取餘的結果。

示例 1:

輸入:n = 2, s1 = “aa”, s2 = “da”, evil = “b”
輸出:51
解釋:總共有 25 個以 ‘a’ 開頭的好字符串:“aa”,“ac”,“ad”,…,“az”。還有 25 個以 ‘c’ 開頭的好字符串:“ca”,“cc”,“cd”,…,“cz”。最後,還有一個以 ‘d’ 開頭的好字符串:“da”。
示例 2:

輸入:n = 8, s1 = “leetcode”, s2 = “leetgoes”, evil = “leet”
輸出:0
解釋:所有字典序大於等於 s1 且小於等於 s2 的字符串都以 evil 字符串 “leet” 開頭。所以沒有好字符串。
示例 3:

輸入:n = 2, s1 = “gx”, s2 = “gz”, evil = “x”
輸出:2

提示:

s1.length == n
s2.length == n
1 <= n <= 500
1 <= evil.length <= 50
所有字符串都只包含小寫英文字母。

思路

數位dp的變形 + KMP。把問題規約爲求長度爲n,小於等於目標串target且不含子串pattern的字符串個數,這就是countString方法的功能。dp[i][j][s]表示匹配到目標串target位置到i-1,匹配模式串pattern位置到j,狀態s是一個二進制,s=0表示之前的各位沒有達到上界(之前每一位都與目標串target相等),s=1表示達到上界。字符串匹配過程借鑑KMP算法的方式,計算next數組。時間複雜度O(nm)n爲目標串target的長度,m爲模式串pattern的長度。
注意減法之後進行求餘出現負數的情況。

代碼

class Solution {
    private static final int mod = 1000000007;
    private int[][][] dp;       
    // dp[i][j][s]: match index of target string `i`; match index of pattern string `j`; binary state, 1 for reach upper bound
    
    /**
     * Calculate number of strings <= {@code str} and without substring {@code evil}  
     */
    private int countString(int n, String str, String evil) {
        int m = evil.length(), i = 0, j = 0, k = 0, s = 0, ns = 0;
        dp = new int[n+1][m][2];
        
        // Calculate {@code next} array of {@code evil} by KMP
        int[] next = new int[m];
        for(j = 1 ; j < m ; ++j) { 
            while (evil.charAt(i) != evil.charAt(j) && i > 0) {
                i = next[i-1];
            }
            if(evil.charAt(i) == evil.charAt(j)) {
                ++i;
                next[j] = i;
            }
            else {
                next[j] = 0;
            }
        }
        
        // Do dynamic programming
        char[] upperBounds = new char[2];
        upperBounds[0] = 'z';                       // s = 0
        dp[0][0][1] = 1;
        for (i=1; i<=n; ++i) {
            for (j=0; j<m; ++j) {
                upperBounds[1] = str.charAt(i-1);   // s = 1
                for (s=0; s<=1; ++s) {
                    for (char ch='a'; ch<=upperBounds[s]; ++ch) {
                        k = j;
                        while (ch != evil.charAt(k) && k > 0) {
                            k = next[k-1];
                        }
                        if (ch == evil.charAt(k)) {
                            ++k;
                        }
                        if (k == m) {
                            continue;
                        }
                        if (s == 1 && ch == str.charAt(i-1)) {
                            ns = 1;
                        } else {
                            ns = 0;
                        }
                        dp[i][k][ns] = (dp[i][k][ns] + dp[i-1][j][s]) % mod;
                    }
                }
            }
        }
        
        // Calculate answer
        int ans = 0;
        for (j=0; j<m; ++j) {
            for (s=0; s<=1; ++s) {
                ans = (ans + dp[n][j][s]) % mod;
            }
        }
        return ans;
    }
    
    public int findGoodStrings(int n, String s1, String s2, String evil) {
        int tail = s1.contains(evil)? 0: 1, ans = 0;
        ans = (countString(n, s2, evil) - countString(n, s1, evil)) % mod;
        if (ans < 0) {
            ans = ans + mod;
        }
        ans = (ans + tail) % mod;
        return ans;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章