题目来源于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 。下图描述的算法用于找出正整数数组中最大的元素。
请你生成一个具有下述属性的数组 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];
}
}