LeetCode Weekly Contest 185

5388. 重新格式化字符串

給你一個混合了數字和字母的字符串 s,其中的字母均爲小寫英文字母。

請你將該字符串重新格式化,使得任意兩個相鄰字符的類型都不同。也就是說,字母后面應該跟着數字,而數字後面應該跟着字母。

請你返回 重新格式化後 的字符串;如果無法按要求重新格式化,則返回一個 空字符串 。

示例 1:

輸入:s = “a0b1c2”
輸出:“0a1b2c”
解釋:“0a1b2c” 中任意兩個相鄰字符的類型都不同。 “a0b1c2”, “0a1b2c”, “0c2a1b” 也是滿足題目要求的答案。
示例 2:

輸入:s = “leetcode”
輸出:""
解釋:“leetcode” 中只有字母,所以無法滿足重新格式化的條件。
示例 3:

輸入:s = “1229857369”
輸出:""
解釋:“1229857369” 中只有數字,所以無法滿足重新格式化的條件。
示例 4:

輸入:s = “covid2019”
輸出:“c2o0v1i9d”
示例 5:

輸入:s = “ab123”
輸出:“1a2b3”

提示:

1 <= s.length <= 500
s 僅由小寫英文字母和/或數字組成。

代碼

class Solution:
    def reformat(self, s: str) -> str:
        ret = ""
        chs = list()
        nums = list()
        for ch in s:
            if ch >= '0' and ch <= '9':
                nums.append(ch)
            else:
                chs.append(ch)
        lchs = len(chs)
        lnums = len(nums)
        if lchs == lnums:
            for i in range(lchs):
                ret += chs[i] + nums[i]
        elif lchs == lnums + 1:
            for i in range(lnums):
                ret += chs[i] + nums[i]
            ret += chs[-1]
        elif lnums == lchs + 1:
            for i in range(lchs):
                ret += nums[i] + chs[i]
            ret += nums[-1]
        return ret

5389. 點菜展示表

給你一個數組 orders,表示客戶在餐廳中完成的訂單,確切地說, orders[i]=[customerNamei,tableNumberi,foodItemi] ,其中 customerNamei 是客戶的姓名,tableNumberi 是客戶所在餐桌的桌號,而 foodItemi 是客戶點的餐品名稱。

請你返回該餐廳的 點菜展示表 。在這張表中,表中第一行爲標題,其第一列爲餐桌桌號 “Table” ,後面每一列都是按字母順序排列的餐品名稱。接下來每一行中的項則表示每張餐桌訂購的相應餐品數量,第一列應當填對應的桌號,後面依次填寫下單的餐品數量。

注意:客戶姓名不是點菜展示表的一部分。此外,表中的數據行應該按餐桌桌號升序排列。

示例 1:

輸入:orders = [[“David”,“3”,“Ceviche”],[“Corina”,“10”,“Beef Burrito”],[“David”,“3”,“Fried Chicken”],[“Carla”,“5”,“Water”],[“Carla”,“5”,“Ceviche”],[“Rous”,“3”,“Ceviche”]]
輸出:[[“Table”,“Beef Burrito”,“Ceviche”,“Fried Chicken”,“Water”],[“3”,“0”,“2”,“1”,“0”],[“5”,“0”,“1”,“0”,“1”],[“10”,“1”,“0”,“0”,“0”]]
解釋:
點菜展示表如下所示:
Table,Beef Burrito,Ceviche,Fried Chicken,Water
3 ,0 ,2 ,1 ,0
5 ,0 ,1 ,0 ,1
10 ,1 ,0 ,0 ,0
對於餐桌 3:David 點了 “Ceviche” 和 “Fried Chicken”,而 Rous 點了 “Ceviche”
而餐桌 5:Carla 點了 “Water” 和 “Ceviche”
餐桌 10:Corina 點了 “Beef Burrito”
示例 2:

輸入:orders = [[“James”,“12”,“Fried Chicken”],[“Ratesh”,“12”,“Fried Chicken”],[“Amadeus”,“12”,“Fried Chicken”],[“Adam”,“1”,“Canadian Waffles”],[“Brianna”,“1”,“Canadian Waffles”]]
輸出:[[“Table”,“Canadian Waffles”,“Fried Chicken”],[“1”,“2”,“0”],[“12”,“0”,“3”]]
解釋:
對於餐桌 1:Adam 和 Brianna 都點了 “Canadian Waffles”
而餐桌 12:James, Ratesh 和 Amadeus 都點了 “Fried Chicken”
示例 3:

輸入:orders = [[“Laura”,“2”,“Bean Burrito”],[“Jhon”,“2”,“Beef Burrito”],[“Melissa”,“2”,“Soda”]]
輸出:[[“Table”,“Bean Burrito”,“Beef Burrito”,“Soda”],[“2”,“1”,“1”,“1”]]

提示:

1 <= orders.length <= 5 * 10^4
orders[i].length == 3
1 <= customerNamei.length, foodItemi.length <= 20
customerNamei 和 foodItemi 由大小寫英文字母及空格字符 ’ ’ 組成。
tableNumberi 是 1 到 500 範圍內的整數。

思路

二維哈希表

代碼

class Solution {
    public List<List<String>> displayTable(List<List<String>> orders) {
        TreeSet<String> dishes = new TreeSet<>();
        TreeSet<Integer> tables = new TreeSet<>();
        HashMap<Integer, HashMap<String, Integer>> map = new HashMap<>();
        for (List<String> order: orders) {
            String cust = order.get(0), tableStr = order.get(1), food = order.get(2);
            dishes.add(food);
            int table = Integer.parseInt(tableStr);
            tables.add(table);
            if (!map.containsKey(table)) {
                map.put(table, new HashMap<String, Integer>());
            }
            if (!map.get(table).containsKey(food)) {
                map.get(table).put(food, 0);
            }
            map.get(table).put(food, map.get(table).get(food) + 1);
        } 
        LinkedList<List<String>> ret = new LinkedList<>();
        LinkedList<String> head = new LinkedList<>(dishes);
        head.addFirst("Table");
        ret.add(head);
        int i = 0, j = 0;
        Iterator<Integer> iterTable = tables.iterator();
        Iterator<String> iterDish = dishes.iterator();
        while (iterTable.hasNext()) {
            LinkedList<String> row = new LinkedList<>();
            int table = iterTable.next();
            row.add(String.valueOf(table));
            iterDish = dishes.iterator();
            while (iterDish.hasNext()) {
                String food = iterDish.next();
                if (!map.get(table).containsKey(food)) {
                    row.add("0");
                } else {
                    row.add(String.valueOf(map.get(table).get(food)));
                }
            }
            ret.add(row);
        }
        return ret;
    }
}

5390. 數青蛙

給你一個字符串 croakOfFrogs,它表示不同青蛙發出的蛙鳴聲(字符串 “croak” )的組合。由於同一時間可以有多隻青蛙呱呱作響,所以 croakOfFrogs 中會混合多個 “croak” 。請你返回模擬字符串中所有蛙鳴所需不同青蛙的最少數目。

注意:要想發出蛙鳴 “croak”,青蛙必須 依序 輸出 ‘c’, ’r’, ’o’, ’a’, ’k’ 這 5 個字母。如果沒有輸出全部五個字母,那麼它就不會發出聲音。

如果字符串 croakOfFrogs 不是由若干有效的 “croak” 字符混合而成,請返回 -1 。

示例 1:

輸入:croakOfFrogs = “croakcroak”
輸出:1
解釋:一隻青蛙 “呱呱” 兩次
示例 2:

輸入:croakOfFrogs = “crcoakroak”
輸出:2
解釋:最少需要兩隻青蛙,“呱呱” 聲用黑體標註
第一隻青蛙 “crcoakroak”
第二隻青蛙 “crcoakroak”
示例 3:

輸入:croakOfFrogs = “croakcrook”
輸出:-1
解釋:給出的字符串不是 “croak” 的有效組合。
示例 4:

輸入:croakOfFrogs = “croakcroa”
輸出:-1

提示:

1 <= croakOfFrogs.length <= 10^5
字符串中的字符只有 ‘c’, ‘r’, ‘o’, ‘a’ 或者 ‘k’

思路

貪心。貪心主要體現在兩個地方:

  1. 遇到新字母的總是將字母分配給能夠匹配的最早的croak
  2. 每次重用青蛙的時候總是用最早croak完的青蛙
    首先計算每個字符出現的次數(cnts變量)以及每個字符出現的位置(pos變量),按照貪心的原則,可以求出每個青蛙對應的c, r, o, a, k字母位置。如果『兩個字符出現次數不一樣』或『有一個青蛙的c, r, o, a, k字母顛倒』,則返回-1.
    再次遍歷所有青蛙的croak字符組給每個croak分配青蛙同時統計青蛙個數,使用一個先進先出的隊列保存每個croak字符組k字符的位置,代表已經croak完的青蛙。給每個croak分配青蛙的時候,如果隊列非空則取隊首的青蛙,並更新該青蛙croak完的時間重新入隊;如果隊列爲空,則新建一隻青蛙併入隊。

代碼

class Solution {
    private static final HashMap<Character, Integer> map = new HashMap<>() {
        {
            put('c', 0);
            put('r', 1);
            put('o', 2);
            put('a', 3);
            put('k', 4);
        }
    };
    
    public int minNumberOfFrogs(String croakOfFrogs) {
        int len = croakOfFrogs.length();
        if (len % 5 != 0) {
            return -1;
        }
        int n = len / 5, i = 0;
        int[] cnts = new int[5];
        for (char ch: croakOfFrogs.toCharArray()) {
            if (!map.containsKey(ch)) {
                return -1;
            }
            ++cnts[map.get(ch)];
        }
        for (int cnt: cnts) {
            if (cnt != n) {
                return -1;
            }
        }
        int[][] pos = new int[5][n];
        Arrays.fill(cnts, 0);
        for (i=0; i<len; ++i) {
            char ch = croakOfFrogs.charAt(i);
            if (!map.containsKey(ch)) {
                return -1;
            }
            int idx = map.get(ch);
            pos[idx][cnts[idx]++] = i;
        }
        int ans = 0;
        LinkedList<Integer> queue = new LinkedList<>();
        for (i=0; i<n; ++i) {
            if (!(pos[0][i] < pos[1][i] && pos[1][i] < pos[2][i] && pos[2][i] < pos[3][i] && pos[3][i] < pos[4][i])) {
                return -1;
            }
            queue.add(pos[4][i]);
            if (!queue.isEmpty() && queue.getFirst() < pos[0][i]) {
                queue.removeFirst();
            } else {
                ++ans;
            }
        }
        return ans;
    }
}

5391. 生成數組

給你三個整數 n、m 和 k 。下圖描述的算法用於找出正整數數組中最大的元素。
在這裏插入圖片描述
請你生成一個具有下述屬性的數組 arr :

arr 中有 n 個整數。
1 <= arr[i] <= m 其中 (0 <= i < n) 。
將上面提到的算法應用於 arr ,search_cost 的值等於 k 。
返回上述條件下生成數組 arr 的 方法數 ,由於答案可能會很大,所以 必須 對 10^9 + 7 取餘。

示例 1:

輸入:n = 2, m = 3, k = 1
輸出:6
解釋:可能的數組分別爲 [1, 1], [2, 1], [2, 2], [3, 1], [3, 2] [3, 3]
示例 2:

輸入:n = 5, m = 2, k = 3
輸出:0
解釋:沒有數組可以滿足上述條件
示例 3:

輸入:n = 9, m = 1, k = 1
輸出:1
解釋:可能的數組只有 [1, 1, 1, 1, 1, 1, 1, 1, 1]
示例 4:

輸入:n = 50, m = 100, k = 25
輸出:34549172
解釋:不要忘了對 1000000007 取餘
示例 5:

輸入:n = 37, m = 17, k = 7
輸出:418930126

提示:

1 <= n <= 50
1 <= m <= 100
0 <= k <= n

思路

動態規劃. dp[i][x][j]表示:

  • 長度爲i的數組
  • search_costj
  • 數組中最大的元素爲k

邊界條件:

dp[1][x][1] = 1

分兩種情況討論:

  1. 當最大值x出現在數組尾端時,去掉尾端的數組search_cost減1,最大值的取值可以從1到x-1,即sum(dp[i-1][y][j-1]), y=1, 2, .., x-1
  2. 否則去掉尾端的數組search_cost不變,最大值仍爲x,現數組尾端的取值小於等於x即可,對應x * dp[i-1][x][j]
    遞推公式:
dp[i][x][j] = x * dp[i-1][x][j] + sum(dp[i-1][y][j-1]), y=1, 2, .., x-1

優化

直接按遞推公式的時間複雜度爲O(nkm^2),空間複雜度爲O(nmk).
時間複雜度的優化:遞推式中O(m)的sum過程可以用一個sum_dp[i][x][j]數組維護,求dp[i][x][j]的同時更新sum_dp[i][x][j],這樣時間複雜度爲O(nkm)
空間複雜度的優化:在ij維度上,遞推公式只依賴前一個值,因此dp數組這兩個維度可以取消,空間複雜度可以降到O(k)。本人太懶了,代碼裏面空間複雜度的優化就沒有寫

代碼

class Solution {
    private static final int mod = 1000000007;
    
    public int numOfArrays(int n, int m, int k) {
        int[][][] dp = new int[n+1][m+1][k+1], sum_dp = new int[n+1][m+1][k+1];
        for (int x=1; x<=m; ++x) {
            dp[1][x][1] = 1;
            sum_dp[1][x][1] = x;
        }
        for (int i=1; i<=n; ++i) {
            for (int j=1; j<=k; ++j) {
                if (i == 1 && j == 1) {
                    continue;
                }
                for (int x=1; x<=m; ++x) {
                    dp[i][x][j] = sum_dp[i-1][x-1][j-1];
                    dp[i][x][j] = (int)((((long)dp[i][x][j]) + ((long) x) * ((long) dp[i-1][x][j])) % (long)mod);
                    sum_dp[i][x][j] = (sum_dp[i][x-1][j] + dp[i][x][j]) % mod;
                }
            }
        }
        int ans = 0;
        for (int x=1; x<=m; ++x) {
            ans = (ans + dp[n][x][k]) % mod;
        }
        return ans;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章