leetcode第185場周賽

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;
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章