leetcode第185場周賽
時間:2020/02/19 十點半-十二點。只a了第一題,第二題寫了一半,去吃飯了。
第一題、重新格式化字符串
難度:easy,鏈接:https://leetcode-cn.com/problems/reformat-the-string/
給你一個混合了數字和字母的字符串 s,其中的字母均爲小寫英文字母。
請你將該字符串重新格式化,使得任意兩個相鄰字符的類型都不同。也就是說,字母后面應該跟着數字,而數字後面應該跟着字母。
請你返回 重新格式化後 的字符串;如果無法按要求重新格式化,則返回一個 空字符串 。
輸入:s = "a0b1c2"
輸出:"0a1b2c"
解釋:"0a1b2c" 中任意兩個相鄰字符的類型都不同。 "a0b1c2", "0a1b2c", "0c2a1b" 也是滿足題目要求的答案。
我的思路要使相鄰字符類型不同,那麼兩個類型的字符數量差不能多於1個,所以我將這個字符串拆成兩個String來存儲,用String的長度來判斷是否符合要求,符合要求後,每次一邊取一個字符出來,最終拼接成結果。因爲java中String拼接會創建新對象,所以我用StringBuilder代替了String,以減少性能消耗。
比如輸入"a0b1c2",拆成"abc"和"012",長度爲3和3,滿足條件,從兩邊輪流取,從"abc"中取出a,從"012"中取出0,再從"bc"中取出b,從"12"中取出1,最後從"c"中取出c,從"2"中取出2,結果爲"a0b1c2";
class Solution {
public String reformat(String s) {
StringBuilder digit = new StringBuilder();
StringBuilder character = new StringBuilder();
StringBuilder res = new StringBuilder();
for (int i = 0; i < s.length(); i++)
{
if (s.charAt(i) <= 'z' && s.charAt(i) >= 'a')
{
character.append(s.charAt(i));
}
else
{
digit.append(s.charAt(i));
}
}
int len1 = digit.length();
int len2 = character.length();
if (len1 == len2 + 1 || len1 == len2)
{
int index1 = 0;
int index2 = 0;
while (index1 < len1 && index2 < len2)
{
res.append(digit.charAt(index1++));
res.append(character.charAt(index2++));
}
if (index1 < len1) res.append(digit.charAt(index1));
}
else if(len2 == len1 + 1)
{
int index1 = 0;
int index2 = 0;
while (index1 < len1 && index2 < len2)
{
res.append(character.charAt(index2++));
res.append(digit.charAt(index1++));
}
if (index2 < len2) res.append(character.charAt(index2));
}
return res.toString();
}
}
第二題、點菜展示表
難度:medium 鏈接:https://leetcode-cn.com/problems/display-table-of-food-orders-in-a-restaurant/
給你一個數組 orders,表示客戶在餐廳中完成的訂單,確切地說, orders[i]=[customerNamei,tableNumberi,foodItemi] ,其中 customerNamei 是客戶的姓名,tableNumberi 是客戶所在餐桌的桌號,而 foodItemi 是客戶點的餐品名稱。
請你返回該餐廳的 點菜展示表 。在這張表中,表中第一行爲標題,其第一列爲餐桌桌號 “Table” ,後面每一列都是按字母順序排列的餐品名稱。接下來每一行中的項則表示每張餐桌訂購的相應餐品數量,第一列應當填對應的桌號,後面依次填寫下單的餐品數量。
注意:客戶姓名不是點菜展示表的一部分。此外,表中的數據行應該按餐桌桌號升序排列。
輸入: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"
這道題目周賽沒寫完,寫完了有個bug就去吃飯了,回來後改完bug就a了,難度是medium,雖然不難,但得用map套map來解決,還是挺複雜的。用一個<桌號,<這桌點的菜,點的菜的數量>>map來存儲每一週點的菜,用一個Set存儲出現過的菜,因爲結果裏面沒有點的菜也得放到結果中(爲0),最後用Set來組成字段(結果表格的屬性行,需要排序),用map來完成每一行(需要按桌號排序),最後返回結果。
class Solution {
public List<List<String>> displayTable(List<List<String>> orders) {
int ordernum = orders.size();
List<List<String>> res = new ArrayList();
HashSet<String> fooditems = new HashSet();//存放菜名的set
HashMap<String,HashMap<String,Integer>> ordermap = new HashMap();//map,key = 桌號,value = <菜名,點的數量>
for (int i = 0; i < ordernum; i++)//讀取訂單
{
List<String> order = orders.get(i);//第i個訂單
HashMap<String,Integer> map = ordermap.getOrDefault(order.get(1),new HashMap<String,Integer>());
map.put(order.get(2), map.getOrDefault(order.get(2),0) + 1);
ordermap.put(order.get(1),map);
fooditems.add(order.get(2));
}
ArrayList<String> foods = new ArrayList<>(fooditems);
Collections.sort(foods);//將菜名排序
for (Map.Entry<String,HashMap<String,Integer>> entry: ordermap.entrySet())
{
String tableid = entry.getKey();
HashMap<String,Integer> value = entry.getValue();
ArrayList<String> newvalue = new ArrayList();
newvalue.add(tableid);
for (int i = 0; i < foods.size(); i++)
{
newvalue.add(String.valueOf(value.getOrDefault(foods.get(i),0)));
}
res.add(newvalue);
}
Collections.sort(res,(a,b) -> (Integer.valueOf(a.get(0)) - Integer.valueOf(b.get(0)) ));//按桌號排序
foods.add(0,"Table");
res.add(0,foods);
return res;
}
}
第三題、數青蛙
難度:medium 鏈接:https://leetcode-cn.com/problems/minimum-number-of-frogs-croaking/
給你一個字符串 croakOfFrogs,它表示不同青蛙發出的蛙鳴聲(字符串 "croak" )的組合。由於同一時間可以有多隻青蛙呱呱作響,所以 croakOfFrogs 中會混合多個 “croak” 。請你返回模擬字符串中所有蛙鳴所需不同青蛙的最少數目。
注意:要想發出蛙鳴 "croak",青蛙必須 依序 輸出 ‘c’, ’r’, ’o’, ’a’, ’k’ 這 5 個字母。如果沒有輸出全部五個字母,那麼它就不會發出聲音。
如果字符串 croakOfFrogs 不是由若干有效的 "croak" 字符混合而成,請返回 -1 。
輸入:croakOfFrogs = "croakcroak" 輸出:1 解釋:一隻青蛙 “呱呱” 兩次
思路:
因爲一隻青蛙必須按順序輸出croak五個字母,才能輸出下一個。
所以有兩種情況,如果一隻青蛙讀完cro,又來一個c,那麼就需要另一隻青蛙。
如果一直青蛙讀完cro,又來一個r,而因爲沒有讀完c沒讀r的青蛙,所以不存在結果。
所以我們可以用c,r,o,a,k五個變量來存儲讀到c,讀到r,讀到o,讀到a,讀到k的青蛙數。
如果讀到c,那就直接c++,讀到r,需要判斷是否有讀到c的青蛙,如果有,即(c!=0),那麼就可以繼續讀,c--,r++,如果c==0,即不存在讀到c的青蛙,那就發生了錯誤,結果返回-1,讀到o,a,k類似。
而當沒有發生錯誤時,需要的青蛙數等於所有青蛙的和(c+r+o+a+k),因爲和會變,結果就是所有青蛙的和的最大值。
最後也要檢測是否所有的青蛙數是否都讀完了,如果有青蛙沒讀完,那也要返回-1.
class Solution {
public int minNumberOfFrogs(String croakOfFrogs) {
int c = 0,r = 0, o = 0, a = 0, k = 0;//存儲讀到某個字母的青蛙個數
int sum = 0;//當前所需的青蛙數
int res = 0;//最終需要的青蛙數,即max(sum);
for (int i = 0; i < croakOfFrogs.length(); i++)
{
char temp = croakOfFrogs.charAt(i);
if (temp == 'c') //如果讀到c,因爲只有讀到c纔可能需要新青蛙,計算一下sum,更新一下res
{
c++;
sum++;
res = Math.max(sum,res);
}
else if (temp == 'r')//如果讀到r,而沒有讀到的青蛙,那麼顯然出錯了,將res置爲1,break
{
if (c == 0)
{
res = -1;
break;
}
else
{
c--;
r++;
}
}
else if (temp == 'o')
{
if (r == 0)
{
res = -1;
break;
}
else
{
r--;
o++;
}
}
else if (temp == 'a')
{
if (o == 0)
{
res = -1;
break;
}
else
{
o--;
a++;
}
}
else
{
if (a == 0)
{
res = -1;
break;
}
else
{
a--;
k++;
sum--;
}
}
}
if (sum != 0) res = -1;//如果有青蛙沒讀完,那麼也出錯了,返回-1;
return res;
}
}
四、生成數組
難度:hard,鏈接:https://leetcode-cn.com/problems/build-array-where-you-can-find-the-maximum-exactly-k-comparisons/
給你三個整數 n、m 和 k 。下圖描述的算法用於找出正整數數組中最大的元素。
請你生成一個具有下述屬性的數組 arr :
arr 中有 n 個整數。
1 <= arr[i] <= m 其中 (0 <= i < n) 。
將上面提到的算法應用於 arr ,search_cost 的值等於 k 。返回上述條件下生成數組 arr 的 方法數 ,由於答案可能會很大,所以 必須 對 10^9 + 7 取餘。
輸入:n = 2, m = 3, k = 1
輸出:6
解釋:可能的數組分別爲 [1, 1], [2, 1], [2, 2], [3, 1], [3, 2] [3, 3]
輸入:n = 5, m = 2, k = 3 輸出:0 解釋:沒有數組可以滿足上述條件
這道題目可以用三維dp來解決,dp[i][j][t] = 長度爲i的數組, 最大值是t - 1,還剩下j次serach_cost增加機會的方法數
dp[i][j][t] = dp[i-1][j+1][p] + (t+1)*dp[i-1][j][t];
代碼如下:
class Solution {
public int numOfArrays(int n, int m, int k) {
long[][][] dp = new long[n][k + 1][m];//dp[i][j][t] = 長度爲i的數組, 最大值是t - 1,還剩下j次serach_cost增加機會的方法數
for (int i = 0; i < m; i++)
{
dp[0][k-1][i] = 1;
}
for (int i = 1; i < n; i++)
{
for (int j = 0; j < k + 1 ; j++)
{
for (int t = 0; t < m; t++)
{
for (int p = 0; p < t; p++)
{
if (j != k ) dp[i][j][t] += dp[i-1][j+1][p] ;//第i個數比之前的最大值要大
}
dp[i][j][t] += (t + 1) * dp[i-1][j][t];//第i個數比之前的最大值要小於等於
dp[i][j][t] %= 1000000007;
}
}
}
long res = 0;
for (int i = 0; i < m; i++)
{
res += dp[n-1][0][i] ;
}
res %= 1000000007;
return (int)res;
}
}