LeetCode 第185场周赛 题解

题目来源于LeetCode

第1题 来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reformat-the-string

第2题 来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/display-table-of-food-orders-in-a-restaurant

第3题 来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-number-of-frogs-croaking

第4题 来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/build-array-where-you-can-find-the-maximum-exactly-k-comparisons


第1题:重新格式化字符串

给你一个混合了数字和字母的字符串 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 仅由小写英文字母和/或数字组成。
题目分析

这个代码有点菜,重复的地方很多,但是思路很简单,分别找到数字和字母,然后判断长度,然后合并

代码实现

public class _2020_04_19_01_ReformatTheString {
    public static void main(String[] args) {
        String s = "covid201009";
        System.out.println(reformat(s));
    }

    public static String reformat(String s) {
        StringBuilder sbNum = new StringBuilder(s.length());
        StringBuilder sbStr = new StringBuilder(s.length());
        StringBuilder sbRes = new StringBuilder(s.length());
        int numCount = 0;
        int stringCount = 0;
        String temp = null;
        for (int i = 0; i < s.length(); i++) {
            temp = String.valueOf(s.charAt(i));
            if (judge(temp)) {
                numCount++;
                sbNum.append(temp);
            } else {
                stringCount++;
                sbStr.append(temp);
            }
        }
        int index = 0;
        System.out.println(numCount - stringCount);
        if (numCount - stringCount == 1) {
            while (index != stringCount) {
                sbRes.append(sbNum.charAt(index)).append(sbStr.charAt(index));
                index++;
            }
            sbRes.append(sbNum.charAt(index));
            return sbRes.toString();
        } else if (numCount - stringCount == -1) {
            while (index != numCount) {
                sbRes.append(sbStr.charAt(index)).append(sbNum.charAt(index));
                index++;
            }
            sbRes.append(sbStr.charAt(index));
            return sbRes.toString();
        } else if (numCount - stringCount == 0) {
            while (index != numCount) {
                sbRes.append(sbStr.charAt(index)).append(sbNum.charAt(index));
                index++;
            }
            return sbRes.toString();
        } else {
            return "";
        }

    }

    public static boolean judge(String s) {
        String[] temp = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
        for (String t : temp) {
            if (s.equals(t)) {
                return true;
            }
        }
        return false;
    }
}
第2题:点菜展示表

给你一个数组 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 范围内的整数。
题目分析

1.存储订单信息 tableId -> {foodName -> foodCount} (treemap),记录所有菜品名(set)
2.构造每桌每个菜品数量
3.构造title

作者:bigpotato-3
链接:https://leetcode-cn.com/problems/display-table-of-food-orders-in-a-restaurant/solution/tong-su-yi-dong-javashi-xian-by-bigpotato-3/
来源:力扣(LeetCode)

代码实现

public class _2020_04_19_02_DisplayTableOfFoodOrdersInARestaurant {
    public static void main(String[] args) {
        //To Do Init
    }

    public List> displayTable(List> orders) {
        //tableId -> {foodName -> foodCount}
        TreeMap> tableFoodMap = new TreeMap<>(new Comparator() {
            @Override
            public int compare(String o1, String o2) {
                return Integer.parseInt(o1) - Integer.parseInt(o2);
            }
        });

        Set foodNameSet = new HashSet<>();

        //遍历所有订单,放入tableFoodMap结构中
        for (List order : orders) {
            String tableId = order.get(1);
            String foodName = order.get(2);

            foodNameSet.add(foodName);

            if (tableFoodMap.containsKey(tableId)) {
                Map foodCountMap = tableFoodMap.get(tableId);
                foodCountMap.put(foodName, foodCountMap.getOrDefault(foodName, 0) + 1);
            } else {
                Map foodCountMap = new HashMap<>();
                foodCountMap.put(foodName, 1);
                tableFoodMap.put(tableId, foodCountMap);
            }
        }

        //菜品名称按照字母序排序
        List orderedFoodNames = new ArrayList<>(foodNameSet);
        orderedFoodNames.sort(new Comparator() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        });

        List> showMenus = new ArrayList<>();
        //构造每桌每个菜品数量
        for (Map.Entry> entry : tableFoodMap.entrySet()) {
            String tableId = entry.getKey();
            List showMenu = new ArrayList<>();
            showMenu.add(tableId);
            for (String foodName : orderedFoodNames) {
                showMenu.add(entry.getValue().getOrDefault(foodName, 0) + "");
            }
            showMenus.add(showMenu);
        }
        //构造标题
        orderedFoodNames.add(0, "Table");
        List> res = new ArrayList<>();
        res.add(orderedFoodNames);
        res.addAll(showMenus);

        return res;
    }
}
第3题:数青蛙

给你一个字符串 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分解为5个状态,维护每个状态下青蛙的个数,青蛙必须处于之前状态的才能进入下一个状态
作者:thebestwj
链接:https://leetcode-cn.com/problems/minimum-number-of-frogs-croaking/solution/java-shi-jian-on-kong-jian-o1-jie-fa-jian-ji-yi-do/
来源:力扣(LeetCode)

代码演示

public class _2020_04_19_03_MinimumNumberOfFrogsCroaking {

    public static void main(String[] args) {
        System.out.println(minNumberOfFrogs("crcoakroak"));
    }


    public static int minNumberOfFrogs2(String croakOfFrogs) {
        int c = 0, r = 0, o = 0, a = 0, k = 0;
        char[] chars = croakOfFrogs.toCharArray();
        int res = 0;
        for (int i = 0; i < chars.length; i++) {
            if (chars[i] == 'c') {
                if (k > 0) {
                    k--;
                } else {
                    res++;
                }
                c++;
            } else if (chars[i] == 'r') {
                c--;
                r++;
            } else if (chars[i] == 'o') {
                r--;
                o++;
            } else if (chars[i] == 'a') {
                o--;
                a++;
            } else if (chars[i] == 'k') {
                a--;
                k++;
            }
            if (c < 0 || r < 0 || o < 0 || a < 0) {
                break;
            }
        }
        if (c != 0 || r != 0 || o != 0 || a != 0) {
            return -1;
        }
        return res;

    }

    public static int minNumberOfFrogs(String croakOfFrogs) {
        //5个状态分别代表叫了c,r,o,a,k(叫完了)
        int[] state = new int[5];
        for (char c : croakOfFrogs.toCharArray()) {
            switch (c) {
                case 'c':
                    //有叫完一次的青蛙,可以重新开始叫
                    if (state[4] > 0) {
                        state[4]--;
                    }
                    state[0]++;
                    break;
                case 'r':
                    //状态转换
                    if (state[0] > 0) {
                        state[1]++;
                        state[0]--;
                    } else {
                        //必须有处于之前状态的青蛙才能进入下一个状态
                        return -1;
                    }
                    break;
                case 'o':
                    if (state[1] > 0) {
                        state[2]++;
                        state[1]--;
                    } else {
                        return -1;
                    }
                    break;
                case 'a':
                    if (state[2] > 0) {
                        state[3]++;
                        state[2]--;
                    } else {
                        return -1;
                    }
                    break;
                case 'k':
                    if (state[3] > 0) {
                        state[4]++;
                        state[3]--;
                    } else {
                        return -1;
                    }
                    break;
                default:
                    return -1;
            }
        }
        //最后不能有处于中间状态的青蛙
        return state[0] + state[1] + state[2] + state[3] == 0 ? state[4] : -1;
    }
}

第4题:生成数组

给你三个整数 n、m 和 k 。下图描述的算法用于找出正整数数组中最大的元素。


LeetCode 第185场周赛 题解_第1张图片

请你生成一个具有下述属性的数组 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算法 动态规划

代码实现

public class _2020_04_19_04_FindTheMaximumArrays {

    private static int mod = (int) 1e9 + 7;

    private int n, m, k;

    public int numOfArrays(int n, int m, int k) {
        long[][][] dp = new long[n + 1][m + 1][k + 1];
        for (int i = 0; i <= n; i++) {
            for (int j = 0; j <= m; j++) {
                Arrays.fill(dp[i][j], -1);
            }
        }
        long res = 0;
        this.m = m;
        this.n = n;
        this.k = k;
        for (int i = 1; i <= m; i++) {
            res += dfs(dp, 1, i, k - 1);
            res %= mod;
        }
        return (int) res;
    }

    // 分别表示当前的位置,截至目前最大的元素,剩余的峰值数量
    private long dfs(long[][][] dp, int cur, int max, int k) {
        if (cur == n) {
            //判断是否符合条件
            return k == 0 ? 1 : 0;
        }
        if (dp[cur][max][k] != -1) {
            return dp[cur][max][k];
        }
        //可选max个非峰值数
        dp[cur][max][k] = dfs(dp, cur + 1, max, k) * max % mod;
        if (k > 0) {
            // 依次遍历可选的峰值
            for (int i = max + 1; i <= m; i++) {
                dp[cur][max][k] += dfs(dp, cur + 1, i, k - 1);
                dp[cur][max][k] %= mod;
            }
        }
        return dp[cur][max][k];
    }

}

你可能感兴趣的:(LeetCode 第185场周赛 题解)