力扣第136题:只出现一次的数字 巧用异或
力扣第136题:只出现一次的数字 C语言解法
题目描述
给定一个非空的整数数组 nums
,其中除一个元素只出现一次外,其他每个元素均出现两次。找出那个只出现一次的元素。
示例
示例 1:
输入: nums = [2,2,1]
输出: 1
示例 2:
输入: nums = [4,1,2,1,2]
输出: 4
示例 3:
输入: nums = [1]
输出: 1
提示
1 <= nums.length <= 3 * 10^4
-3 * 10^4 <= nums[i] <= 3 * 10^4
- 除了某个元素只出现一次外,数组中的其他元素都出现两次。
解题思路
1. 异或操作的特性
这道题可以利用异或运算的特性来解决。异或操作(^
)有以下几个重要特性:
- a ⊕ a = 0 a \oplus a = 0 a⊕a=0:任何数与它自己异或的结果是 0。
- a ⊕ 0 = a a \oplus 0 = a a⊕0=a:任何数与 0 异或的结果是该数本身。
- 异或运算满足交换律和结合律。
基于这些特性,我们可以对所有数组中的数字进行一次异或运算,结果就是只出现一次的数字。因为数组中除了一个数字外,其余数字都出现了两次,且由于异或的特性,成对的数字会相互抵消,最终结果就是那个只出现一次的数字。
2. 算法步骤
- 初始化一个变量
result
为 0。 - 遍历数组中的每个数字,对
result
进行异或操作。 - 最终
result
中的值就是只出现一次的数字。
3. 时间复杂度与空间复杂度
- 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组的长度。我们只需要遍历一次数组。
- 空间复杂度: O ( 1 ) O(1) O(1),只使用了常数级别的额外空间。
C语言代码实现
#include <stdio.h>int singleNumber(int* nums, int numsSize) {int result = 0;for (int i = 0; i < numsSize; i++) {result ^= nums[i]; // 对每个数字进行异或操作}return result; // 最终返回只出现一次的数字
}int main() {int nums1[] = {2, 2, 1};int nums2[] = {4, 1, 2, 1, 2};int nums3[] = {1};printf("Result 1: %d\n", singleNumber(nums1, 3)); // 输出 1printf("Result 2: %d\n", singleNumber(nums2, 5)); // 输出 4printf("Result 3: %d\n", singleNumber(nums3, 1)); // 输出 1return 0;
}
代码解释
-
singleNumber
函数:- 初始化
result
为 0。 - 遍历数组,对每个元素进行异或操作。
- 最终返回
result
,即那个只出现一次的数字。
- 初始化
-
main
函数:- 测试了三组数据,分别是
[2, 2, 1]
、[4, 1, 2, 1, 2]
和[1]
,并输出结果。
- 测试了三组数据,分别是
异或运算的过程示例
假设输入数组为 [4, 1, 2, 1, 2]
,我们逐个进行异或运算:
result = 0 ^ 4 = 4
result = 4 ^ 1 = 5
result = 5 ^ 2 = 7
result = 7 ^ 1 = 6
result = 6 ^ 2 = 4
最终结果为 4
,即只出现一次的数字。
4. 时间复杂度分析
时间复杂度是 O ( n ) O(n) O(n),其中 n n n 是数组的长度。因为我们只需要遍历一次数组,对每个元素进行一次常数时间的异或操作。
5. 空间复杂度分析
空间复杂度是 O ( 1 ) O(1) O(1),只用了常数级别的额外空间来存储 result
变量。
总结
通过利用异或运算的特性,这道题可以在 O ( n ) O(n) O(n) 时间复杂度内解决,而且只需要 O ( 1 ) O(1) O(1) 的空间复杂度。异或操作的特性使得我们能够快速找到只出现一次的元素,非常高效。