同事发了18万年终奖,领导只收到6万,以为是发错了,去找总监核实,结果总监说:你作为领导,绩效不理想。但你下属绩效好,这很正常。
有网友说,公司发年终奖,他同事到手18万,领导自己才6万。领导一看人都懵了,第一反应不是反思,而是觉得财务是不是发错了,赶紧跑去找总监核实。
结果总监一句话直接把场面干安静了:你是领导没错,但你绩效不理想。你下属绩效好,奖金高,很正常。
这事最扎心的点就在这儿。很多人当了领导之后,总觉得自己天然就该比下面人拿得多,毕竟职位高嘛。可公司真按结果分钱的时候,脸就有点挂不住了。
下属干得好,拿18万;领导带队没带出成绩,拿6万。听着刺耳,但逻辑还真没啥毛病。
估计领导去问之前,还想着能查出个系统bug。没想到最后查出来,bug是自己。HR看完都得低头喝口水。
牌都摊开了,最小那张还没被用掉,你却想从中间开始凑顺子,这种写法我第一眼就不太信。
“一手顺子”这个题,坑不在代码长,坑在顺序。给你一堆牌 hand,每组必须是 groupSize 张连续牌,问能不能刚好分完。
比如:
hand = [1,2,3,6,2,3,4,7,8]
groupSize = 3
可以拆成:
[1,2,3]
[2,3,4]
[6,7,8]
但如果最小的牌是 1,那它没得选。它只能作为某一组的开头,必须去找 2、3、...。你让它去当后面的牌,不现实,因为没有更小的牌在前面补。
所以这题我一般不搞花活,就盯着最小牌处理。
先把每张牌出现次数统计起来,还要能按牌面从小到大拿,Java 里用 TreeMap 正合适。
代码可以这么写:
import java.util.Map;
import java.util.TreeMap;
classSolution{
publicbooleanisNStraightHand(int[] hand, int groupSize){
if (hand == null || hand.length == 0) {
returnfalse;
}
if (hand.length % groupSize != 0) {
returnfalse;
}
TreeMap<Integer, Integer> cardBox = new TreeMap<>();
for (int card : hand) {
cardBox.put(card, cardBox.getOrDefault(card, 0) + 1);
}
while (!cardBox.isEmpty()) {
int start = cardBox.firstKey();
for (int card = start; card < start + groupSize; card++) {
Integer left = cardBox.get(card);
if (left == null) {
returnfalse;
}
if (left == 1) {
cardBox.remove(card);
} else {
cardBox.put(card, left - 1);
}
}
}
returntrue;
}
}
这里有个细节,别小看这句:
int start = cardBox.firstKey();
每次都从当前最小的牌开拆。
比如当前最小是 5,那它必须拉着 6、7、8... 组成一组。要是 6 不在,直接失败。因为这张 5 已经没有别的地方能去了。
有些写法会先排序数组,再用 HashMap 扣次数,也能做。但我不太喜欢那种写法,循环里会反复扫已经没用的牌,代码看着也容易绕。TreeMap 的好处是:谁还没用完,谁就在表里;谁用完了,直接删掉。现场排问题时,这种结构更顺眼。
再看一个容易误判的例子:
hand = [1,2,3,4,5]
groupSize = 4
长度 5 不能被 4 整除,别往后算了,直接 false。这个判断要放前面,不然就是白跑。
还有这种:
hand = [1,2,3,4,6,7,8,9]
groupSize = 4
第一组可以是 [1,2,3,4],剩下 [6,7,8,9],也可以。
如果是:
hand = [1,2,3,4,6,7,8,10]
groupSize = 4
第一组扣完后,最小是 6,需要 6、7、8、9,结果 9 没有,失败。别被后面的 10 晃了眼,它补不了 9 的坑。
这题的判断顺序就一句话:最小的牌先安排,安排不了就别挣扎。复杂度主要在 TreeMap 的增删查上,大概是 O(n log n),够用了。 算法题有时候不是看你能不能写得高级,是看你有没有抓住那个“最没退路”的元素。最小牌,就是这题里最没退路的那张。