问题描述
小明和小红在玩一个有趣的套碗游戏。桌上有 n 个碗排成一排,每个碗下面都藏着一张纸条,纸条上写着一个整数。游戏规则是:每次可以拿走两个相邻的碗,但必须满足这两个碗下的数字相同。当所有碗都被拿走后,如果剩下最后一个碗无法配对,那么这个碗就是"幸运碗"。
经过数学证明,无论以何种顺序拿碗,最后剩下的数字一定是唯一的(这是因为配对消除操作满足交换律和结合律,最终结果与顺序无关)。因此,问题可以简化为:在给定的整数序列中,找出那个只出现一次的数字(其他数字都恰好出现两次)。
要求:
- 设计一个算法,在 O(n) 时间内找出幸运数字。
- 尽量使用 O(1) 的额外空间,展现算法优化能力。
测试样例
样例1:
输入:
bowls = [5, 2, 2, 3, 3, 5, 1]输出:1解释:序列中数字1只出现一次,其他数字都出现两次。无论按什么顺序拿碗(比如先拿2和2,再拿3和3,然后拿5和5),最后总会剩下数字1。
样例2:
输入:
bowls = [8, 8, 9, 9, 10, 10, 11]输出:11解释:序列中数字11只出现一次,其他数字都出现两次。因此11是唯一无法配对的数字,会留在幸运碗中。
样例3:
输入:
bowls = [4, 4, 6, 6, 7, 7, 0, 0, 100]输出:100解释:序列中数字100只出现一次,其他数字都出现两次。因此100是最终剩下的幸运数字。
约束条件
- 1 ≤ bowls.length ≤ 1001
- 0 ≤ bowlsi ≤ 1000
- 碗的数量为奇数
- 除了一个数字只出现一次外,其余每个数字都恰好出现两次
提示
- 考虑使用位运算中的异或操作,因为异或操作具有以下性质:
- a ^ a = 0
- a ^ 0 = a
- 异或操作满足交换律和结合律
- 通过对所有数字进行异或操作,出现两次的数字会相互抵消为0,最终剩下的就是只出现一次的数字。
程序代码
#include <stdio.h>
int findLuckyBowl(int* bowls, int bowlsSize) {
int result = 0;
for (int i = 0; i < bowlsSize; i++) {
result ^= bowlsi;
}
return result;
}
int main() {
int bowls1\[\] = {5, 2, 2, 3, 3, 5, 1};
int bowls2\[\] = {8, 8, 9, 9, 10, 10, 11};
int bowls3\[\] = {4, 4, 6, 6, 7, 7, 0, 0, 100};
printf("%d\n", findLuckyBowl(bowls1, 7)); // 1
printf("%d\n", findLuckyBowl(bowls2, 7)); // 11
printf("%d\n", findLuckyBowl(bowls3, 9)); // 100
return 0;
}
cpp
#include <stdio.h>
int findLuckyBowl(int* bowls, int bowlsSize) {
int result = 0;
for (int i = 0; i < bowlsSize; i++) {
result ^= bowls[i];
}
return result;
}
int main() {
int bowls1[] = {5, 2, 2, 3, 3, 5, 1};
int bowls2[] = {8, 8, 9, 9, 10, 10, 11};
int bowls3[] = {4, 4, 6, 6, 7, 7, 0, 0, 100};
printf("%d\n", findLuckyBowl(bowls1, 7)); // 1
printf("%d\n", findLuckyBowl(bowls2, 7)); // 11
printf("%d\n", findLuckyBowl(bowls3, 9)); // 100
return 0;
}
运行结果
