Funplus 笔试原题 2

278 阅读3分钟

题目描述

趣小加非常喜爱玩扑克,现在需要从若干副扑克牌中随机抽5张牌,判断是不是一个顺子,即这5张牌是不是连续的。

2~10为数字本身,A为1,J为11,Q为12,K为13;

而 大、小王为0,可以看成任意牌。

另外,"10,J(11),Q (12),K(13),A(1)"也是顺子。

请你帮助趣小加实现上述功能 )补充说明 数组长度为5 数组的数取值为[0,13].

思路

思路 1

本题有一种情况需要特殊处理:例如 0 10 11 12 1 这个序列,它可以转换为 10 J Q K A,因此这里的 A 实际上是作 14 来用的。

我们还应该知道:J Q K A 2 所有跨越 K 的序列都是非法的;

因此我们确定了要处理的两种情况

(1)对于第一种情况的处理,我们先遍历一趟卡片,统计通用牌(大小王)的数量,然后将 0 从数组中移除后排序,接着继续计算它们之间的 gap 差,最后保证 gap 差 <= 0 的个数就是合法顺子;

(2)如果第一种情况没通过,进入第二种情况的处理,对移除了 0 的数组进行排序,判断最小值是否为 1(按照我们之前的分析,想要凑成 10 J Q K A),那么最小值此时必须为 1,如果是将其转换为 14(还需要进行排序);接着走一遍(1)的处理流程即可。

代码

package main

import (
	"fmt"
	"sort"
)

func FuncA(cards []int) {

	zeros := 0
	for i := 0; i < len(cards); i++ {
		if cards[i] == 0 {
			zeros++
		}
	}

	cardsWithoutZero := make([]int, 0, len(cards)-zeros)
	for _, num := range cards {
		if num != 0 {
			cardsWithoutZero = append(cardsWithoutZero, num)
		}
	}
	sort.Ints(cardsWithoutZero)

	// A 作为 1 使用时
	gaps := 0
	for i := 1; i < len(cardsWithoutZero); i++ {
		gap := cardsWithoutZero[i] - cardsWithoutZero[i-1]
		if gap > 1 {
			gaps += gap - 1
		}
	}
	if gaps <= zeros {
		fmt.Println(true)
		return
	}
	gaps = 0
	// 10 11 12 13 A 因此考虑到 A 时,顺子最小值此时必须为 A
	// 一旦不是 A,比如是 2,那么 J Q K A 2 不是合法的
	if cardsWithoutZero[0] != 1 {
		fmt.Println(false)
		return
	}
	cardsWithoutZero[0] = 14
	sort.Ints(cardsWithoutZero)

	for i := 1; i < len(cardsWithoutZero); i++ {
		gap := cardsWithoutZero[i] - cardsWithoutZero[i-1]
		if gap > 1 {
			gaps += gap - 1
		}
	}
	if gaps <= zeros {
		fmt.Println(true)
		return
	}
	fmt.Println(false)
}

图示

image.png

思路 2

先对数组进行排序,然后使用 joker 记录大小王的个数,最后将最大的牌和非王的最小牌(刚好下标就是 joker)的差值和 4 比较即可。

第二种情况的处理方式和思路 1 是类似的,判断第一个非王最小牌是否为 1,如果不是直接返回 false,如果是的话,则判断 14 和非王最小牌的差值是否小于等于 4。

代码

package main

import "sort"

const (
	A = 14
)

func isStraight(nums []int) bool {
	sort.Ints(nums)
	// 用于记录大小王的数量
	joker := 0
	// 遍历数组,计算大小王数量,并检查是否有连续的数字
	for i := 0; i < len(nums)-1; i++ {
		if nums[i] == 0 { // 如果是大小王
			joker++ // 计数增加
		} else if i != len(nums)-1 && nums[i] == nums[i+1] { // 如果有重复的数字,直接返回false
			return false
		}
	}
	// 检查最大值与最小值(除去大小王)之差是否小于等于4,是则可以组成顺子
	// joker 值刚好指向第一个非大小王的牌
	if nums[len(nums)-1]-nums[joker] <= 4 {
		return true
	}
	if nums[joker] != 1 {
		return false
	}
	if A-nums[joker+1] <= 4 {
		return true
	}
	return false
}

图示

image.png