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’
思路
貪心。貪心主要體現在兩個地方:
- 遇到新字母的總是將字母分配給能夠匹配的最早的croak
- 每次重用青蛙的時候總是用最早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_cost
爲j
- 數組中最大的元素爲
k
邊界條件:
dp[1][x][1] = 1
分兩種情況討論:
- 當最大值
x
出現在數組尾端時,去掉尾端的數組search_cost
減1,最大值的取值可以從1到x-1
,即sum(dp[i-1][y][j-1]), y=1, 2, .., x-1
- 否則去掉尾端的數組
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)
空間複雜度的優化:在i
和j
維度上,遞推公式只依賴前一個值,因此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;
}
}