package com.darling.boot.order.od.od12;
import java.util.*;
/**
* 整理扑克牌
* 题目描述: 给定一组数字,表示扑克牌的牌面数字,忽略扑克牌的花色,请按如下规则对这一组扑克牌进行整理:
* 步骤1、
* 对扑克牌进行分组,形成组合牌,规则如下:
* 当牌面数字相同张数大于等于4时,组合牌为“炸弹”;
* 3张相同牌面数字 + 2张相同牌面数字,且3张牌与2张牌不相同时,组合牌为“葫芦”;
* 3张相同牌面数字,组合牌为“三张”;
* 2张相同牌面数字,组合牌为“对子”;
* 剩余没有相同的牌,则为“单张”;
* <p>
* 步骤2、
* 对上述组合牌进行由大到小排列,规则如下:
* 不同类型组合牌之间由大到小排列规则:“炸弹” > “葫芦” > “三张” > “对子” > “单张”;
* 相同类型组合牌之间,除“葫芦”外,按组合牌全部牌面数字加总由大到小排列;
* “葫芦”则先按3张相同牌面数字加总由大到小排列,3张相同牌面数字加总相同时,再按另外2张牌面数字加总由大到小排列;
* 由于“葫芦”>“三张”,因此如果能形成更大的组合牌,也可以将“三张”拆分为2张和1张,其中的2张可以和其它“三张”重新组合成“葫芦”,剩下的1
* 张为“单张”
* <p>
* 步骤3、
* 当存在多个可能组合方案时,按如下规则排序取最大的一个组合方案:
* 依次对组合方案中的组合牌进行大小比较,规则同上;
* 当组合方案A中的第n个组合牌大于组合方案B中的第n个组合牌时,组合方案A大于组合方案B;
* 输入描述: 第一行为空格分隔的N个正整数,每个整数取值范围[1,13],N的取值范围[1,1000]
* 输出描述: 经重新排列后的扑克牌数字列表,每个数字以空格分隔
* 示例
* 示例1
* 输入: 1 3 3 3 2 1 5
* 输出: 3 3 3 1 1 5 2
* <p>
* 示例2
* 输入: 4 4 2 1 2 1 3 3 3 4
* 输出: 4 4 4 3 3 2 2 1 1 3
* <p>
* 输入: 4 4 2 1 2 1 3 3 3 4 5 5 5
* 输出: 5 5 5 4 4 3 3 3 2 2 1 1 4
*
* 解题思路:
* 本题比较复杂,
* 主要步骤分为以下几步:
* 1:首先用一个map来存放每个面值对应的个数,key是面值,value是个数
* 2:如果有炸弹,处理炸弹的类型,因为题目要求,(相同类型组合牌之间,除“葫芦”外,按组合牌全部牌面数字加总由大到小排列;),
* 所以,得用一个boomMap专门存放,key是面值,value为面值的个数之和,比如面值是5,个数是6,那么value就是5*6=30.
* 按照value进行降序排序,加入到结果集里面
* 3:处理葫芦的情况,如果三张类型的的个数,有两个或者两个以上,先将三张的最大的面值加入结果集,并在num3里移除,方便下面的操作
* 那么分情况讨论,如果没有两张或者,两张的最大的面值小于移除后的三张最大的面值,那么得将三张进行拆开,拆成两张凑成葫芦,剩下一张放入一张nums1里面
* 这里要用while循环,依次操作,知道不能为止
* 如果经过上面的循环后,三张的类型还是>0,那么就不用拆开了,此时其实三张只有一个,按照题目要求进行处理就行
* 4:剩下的就是处理两张和一张了
*
*
*/
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String line = sc.nextLine();
String[] strings = line.split(" ");
//map用来存放每个值对应的个数
Map<Integer, Integer> map = new HashMap<>();
for (String str : strings) {
int key = Integer.parseInt(str);
Integer val = map.getOrDefault(key, 0);
map.put(key, val + 1);
}
List<Integer> res = new ArrayList<>();
List<Integer> nums1 = new ArrayList<>();
List<Integer> nums2 = new ArrayList<>();
List<Integer> nums3 = new ArrayList<>();
List<Integer> nums4 = new ArrayList<>();
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
//如果个数大于等于4,用num4 进行存放
int value = entry.getValue();
int key = entry.getKey();
if (value >= 4) {
nums4.add(key);
} else if (value == 3) {
nums3.add(key);
} else if (value == 2) {
nums2.add(key);
} else {
nums1.add(key);
}
}
if (nums4.size() > 0) {
//这个map专门用来存放不同数值的炸弹,key是num,value是相同面值的个数加起来之和
Map<Integer, Integer> boomMap = new HashMap<>();
for (int num : nums4) {
boomMap.put(num, num * map.get(num));
}
//按照value进行排序,从大到小, (相同类型组合牌之间,除“葫芦”外,按组合牌全部牌面数字加总由大到小排列;)
Set<Map.Entry<Integer, Integer>> entrySet = boomMap.entrySet();
List<Map.Entry<Integer, Integer>> list = new ArrayList<>(entrySet);
list.sort((a1, a2) -> a2.getValue() - a1.getValue());
//将炸弹依次存逐个入到res 的list里面
for (Map.Entry<Integer, Integer> entry : list) {
Integer key = entry.getKey();
Integer value = entry.getValue();
for (int i = 0; i < value; i++) {
res.add(key);
}
}
}
//对下面几个list进行降序排列
nums3.sort((a1, a2) -> a2 - a1);
nums2.sort((a1, a2) -> a2 - a1);
//如果三张 类型的个数有两个或以上
while (nums3.size() > 1) {
res.add(nums3.get(0));
res.add(nums3.get(0));
res.add(nums3.get(0));
nums3.remove(0);
//下面是要把两个三张拆成葫芦的情况,即没有两张,或者三张的面值比两张的大
if (nums2.size() <= 0 || nums3.get(0) > nums2.get(0)) {
//两个放入葫芦里,一个放入单个里面
res.add(nums3.get(0));
res.add(nums3.get(0));
nums1.add(nums3.get(0));
nums3.remove(0);
}else if (nums2.size() > 0) {
//否则 不需要拆三张了,只是单纯的将两张组成葫芦
res.add(nums2.get(0));
res.add(nums2.get(0));
nums2.remove(0);
}
}
//如果三张 类型的个数1个,不需要将三张进行拆开了
while (nums3.size() > 0 ) {
res.add(nums3.get(0));
res.add(nums3.get(0));
res.add(nums3.get(0));
nums3.remove(0);
if (nums2.size() > 0) {
res.add(nums2.get(0));
res.add(nums2.get(0));
nums2.remove(0);
}
}
//将所有的两张加入结果集里面
if (nums2.size() > 0) {
for (int num: nums2) {
res.add(num);
res.add(num);
}
}
if (nums1.size() > 0) {
nums1.sort((a1, a2) -> a2 - a1);
res.addAll(nums1);
}
for (int num: res) {
System.out.print(num + " ");
}
}
}
华为OD题目: 整理扑克牌
最新推荐文章于 2023-07-15 00:19:23 发布