• 扑克牌问题



    前言

    一张扑克有3个属性,每种属性有3种值(A、B、C)
    比如"AAA",第一个属性值A,第二个属性值A,第三个属性值A
    比如"BCA",第一个属性值B,第二个属性值C,第三个属性值A
    给定一个字符串类型的数组cards[],每一个字符串代表一张扑克
    从中挑选三张扑克,一个属性达标的条件是:这个属性在三张扑克中全一样,或全不一样
    挑选的三张扑克达标的要求是:每种属性都满足上面的条件
    比如:“ABC”、“CBC”、“BBC”
    第一张第一个属性为"A"、第二张第一个属性为"C"、第三张第一个属性为"B",全不一样
    第一张第二个属性为"B"、第二张第二个属性为"B"、第三张第二个属性为"B",全一样
    第一张第三个属性为"C"、第二张第三个属性为"C"、第三张第三个属性为"C",全一样
    每种属性都满足在三张扑克中全一样,或全不一样,所以这三张扑克达标
    返回在cards[]中任意挑选三张扑克,达标的方法数

    解题思路

    在这里插入图片描述
    选两张AAA,第三张必须AAA
    在这里插入图片描述

    一共27个牌面,必须选3张不同牌面的可能性有多少种
    如果必选3个牌面,如果它达标的话,那这3个排名的组合数有多少?
    100* 50 * 60
    最暴力的就是27个牌面,有多少不同的三个牌面你都枚举一下
    最后方案就是几个数相乘就行了
    一共27个牌面,每个牌面要跟不要,但是一且超过3种, 就停止,
    到最后正好3个排名,如果发现每一-位都- 样或者每一-位都不一样
    把它们的数量取出来一乘就搞定了

    最重要的技巧就是根据数据量猜解法
    我一看100万张牌,我就知道用牌的角度来想是不对的,
    必须从牌面着手,因为只有27种牌面

    代码

    	public static int ways(String[] cards) {
    		int[] counts = new int[27];
    		for (String s : cards) {
    			char[] str = s.toCharArray();
    			counts[(str[0] - 'A') * 9 + (str[1] - 'A') * 3 + (str[2] - 'A') * 1]++;
    		}
    		int ways = 0;
    		for (int status = 0; status < 27; status++) {
    			int n = counts[status];
    			if (n > 2) {
    				ways += n == 3 ? 1 : (n * (n - 1) * (n - 2) / 6);
    			}
    		}
    		LinkedList<Integer> path = new LinkedList<>();
    		for (int i = 0; i < 27; i++) {
    			if (counts[i] != 0) {
    				path.addLast(i);
    				ways += process2(counts, i, path);
    				path.pollLast();
    			}
    		}
    		return ways;
    	}
    
    	// 之前的牌面,拿了一些    ABC  BBB  ... 
    	// pre = BBB
    	// ABC  ...
    	// pre  = ABC
    	// ABC BBB CAB
    	// pre = CAB
    	// 牌面一定要依次变大,所有形成的有效牌面,把方法数返回
    	public static int process(int[] counts, int pre, LinkedList<Integer> path) {
    		if (path.size() == 3) {
    			return getWays2(counts, path);
    		}
    		int ways = 0;
    		for (int next = pre + 1; next < 27; next++) {
    			if (counts[next] != 0) {
    				path.addLast(next);
    				ways += process2(counts, next, path);
    				path.pollLast();
    			}
    		}
    		return ways;
    	}
    
    	public static int getWays(int[] counts, LinkedList<Integer> path) {
    		int v1 = path.get(0);
    		int v2 = path.get(1);
    		int v3 = path.get(2);
    		for (int i = 9; i > 0; i /= 3) {
    			int cur1 = v1 / i;
    			int cur2 = v2 / i;
    			int cur3 = v3 / i;
    			v1 %= i;
    			v2 %= i;
    			v3 %= i;
    			if ((cur1 != cur2 && cur1 != cur3 && cur2 != cur3) || (cur1 == cur2 && cur1 == cur3)) {
    				continue;
    			}
    			return 0;
    		}
    		v1 = path.get(0);
    		v2 = path.get(1);
    		v3 = path.get(2);
    		return counts[v1] * counts[v2] * counts[v3];
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
  • 相关阅读:
    LeetCode每日一题——895. 最大频率栈
    English语法_介词 - on
    牛客小白月赛55 F 至至子的公司排队
    十五、C++11常用新特性—Lambda表达式
    IDEA生成带参数和返回值注解
    18.常见的loader以及作用的总结
    hadoop 数据抽取
    『现学现忘』Git分支 — 41、分支基本操作(二)
    Android Stuido Gradle build编译报错原因排查
    maven archetype 项目原型
  • 原文地址:https://blog.csdn.net/xiaolu567/article/details/126091862