一张扑克有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[]中任意挑选三张扑克,达标的方法数。
时间紧。思路见代码。
代码用golang编写。代码如下:
import (
"container/list"
"fmt"
)
func main() {
cards := []string{"ABC", "AAC", "ACC"}
ret := ways2(cards)
fmt.Println(ret)
}
func ways2(cards []string) int {
counts := make([]int, 27)
for _, s := range cards {
counts[(s[0]-'A')*9+(s[1]-'A')*3+(s[2]-'A')*1]++
}
ways := 0
for status := 0; status < 27; status++ {
n := counts[status]
if n > 2 {
ways += twoSelectOne(n == 3, 1, n*(n-1)*(n-2)/6)
}
}
path2 := list.New().Init()
for i := 0; i < 27; i++ {
if counts[i] != 0 {
path2.PushBack(i)
ways += process2(counts, i, path2)
path2.Remove(path2.Back())
}
}
return ways
}
func twoSelectOne(c bool, a int, b int) int {
if c {
return a
} else {
return b
}
}
// 之前的牌面,拿了一些 ABC BBB ...
// pre = BBB
// ABC ...
// pre = ABC
// ABC BBB CAB
// pre = CAB
// 牌面一定要依次变大,所有形成的有效牌面,把方法数返回
func process2(counts []int, pre int, path2 *list.List) int {
if path2.Len() == 3 {
return getWays2(counts, path2)
}
ways := 0
for next := pre + 1; next < 27; next++ {
if counts[next] != 0 {
path2.PushBack(next)
ways += process2(counts, next, path2)
path2.Remove(path2.Back())
}
}
return ways
}
func getWays2(counts []int, path2 *list.List) int {
v1 := path2.Front().Value.(int)
v2 := path2.Front().Next().Value.(int)
v3 := path2.Front().Next().Next().Value.(int)
for i := 9; i > 0; i /= 3 {
cur1 := v1 / i
cur2 := v2 / i
cur3 := v3 / i
v1 %= i
v2 %= i
v3 %= i
if (cur1 != cur2 && cur1 != cur3 && cur2 != cur3) || (cur1 == cur2 && cur1 == cur3) {
continue
}
return 0
}
v1 = path2.Front().Value.(int)
v2 = path2.Front().Next().Value.(int)
v3 = path2.Front().Next().Next().Value.(int)
return counts[v1] * counts[v2] * counts[v3]
}
执行结果如下: