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> displayTable(List> orders) {
        int ordernum = orders.size();
        List> res = new ArrayList();
        HashSet fooditems = new HashSet();//存放菜名的set
        HashMap> ordermap = new HashMap();//map,key = 桌号,value = <菜名,点的数量>
        for (int i = 0; i < ordernum; i++)//读取订单
        {
            List order = orders.get(i);//第i个订单
            HashMap map = ordermap.getOrDefault(order.get(1),new HashMap());
            map.put(order.get(2), map.getOrDefault(order.get(2),0) + 1);
            ordermap.put(order.get(1),map);
            fooditems.add(order.get(2));
        }
        ArrayList foods = new ArrayList<>(fooditems);
        Collections.sort(foods);//将菜名排序
        for (Map.Entry> entry: ordermap.entrySet())
        {
            String tableid = entry.getKey();
            HashMap value = entry.getValue();
            ArrayList 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 :

leetcode第185场周赛_第1张图片

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

 

你可能感兴趣的:(leetcode)