🔥题目
从扑克牌中随机抽5张牌,判断是不是一个顺子,即这5张牌是不是连续的。
规则:2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王为 0 ,可以看成任意数字。
输入:[2, 3, 4, 5, 6]
输出:true
输入:[0, 0, 1, 2, 5]
输出:true
☘️解析
理清题意后,我们分析出5张牌是顺子的充要条件为:
1)除大小王外,不能有重复
2)除大小王外,最大值max和最小值min满足:max - min < 5
第二个条件是解题的神来之笔:
没有大小王时,假设五张牌为[1, 2, 3, 4, 5],很容易看出最大最小值之差小于5;有大小王时,假设五张牌为[0, 0, 1, 2, 4],也可以看出最大最小值之差只会更小,不会更大。
这一个判断妙在何处呢?
一来,排除了大小王的干扰;
二来,找最大值/最小值并不需要数组有序,是O(n)的复杂度。
🧊代码
class Solution {
public boolean isStraight(int[] nums) {
int min = Integer.MAX_VALUE;
int max = 0;
Set<Integer> set = new HashSet<>();
for (int num : nums) {
if (num == 0) {
continue;
}
if (set.contains(num)) {
return false;
}
set.add(num);
min = Math.min(min, num);
max = Math.max(max, num);
}
return max - min < 5;
}
}
🌸补充
妙哉妙哉!
🔥题目
写一个函数,求两个整数之和,要求在函数体内不得使用 “+”、“-”、“*”、“/” 四则运算符号。
输入:a = 1,b = 1
输出:2
☘️解析
竟然真的有加减乘除,只使用位运算,也能实现加法 ?!
联想一下数字电路中最简单的1位加法器:
a | b | sum | carry |
---|---|---|---|
0 | 0 | 0 | 0 |
0 | 1 | 1 | 0 |
1 | 0 | 1 | 0 |
1 | 1 | 0 | 1 |
和 sum = a ^ b
进位 carry = (a & b) << 1
因此:a + b = sum + carry
左侧的加法不断被转化为右侧的加法,直到进位为0。
如果你还是不理解这个过程,就用 3 + 7
试试看,这是非常经典的例子。
🧊代码
按照上面的思路写出代码:
class Solution {
public int add(int a, int b) {
int sum = a ^ b;
int carry = ((a & b) << 1);
while (carry != 0) {
carry = ((a & b) << 1);
sum = a ^ b;
a = sum;
b = carry;
}
return sum;
}
}
代码可进一步精简:
class Solution {
public int add(int a, int b) {
while (b != 0) {
int temp = a ^ b;
b = ((a & b) << 1);
a = temp;
}
return a;
}
}
🌸补充
妙哉妙哉!