【LeetCode】136. Single Number
题目:
给定一个非空整数数组,除其中一个元素外,每个元素都出现了两次,找出那个只出现了一次的元素。
例1:
输入: [2,2,1] 输出: 1
例2:
输入: [4,1,2,1,2] 输出: 4
思路:
对数组元素进行依次统计,如果一个元素已经出现了两次,则不再关注,直到找到只出现一次的元素。
#include <stdio.h>
//统计在数组arr中数字k出现的次数,n是数组的大小
int countLetter(int* arr, int n, int k) {
int count = 0;
for (int i=0; i<n; i++) {
if (arr[i] == k) {
count++;
}
}
return count;
}
int singleNumber(int* nums, int numsSize) {
for (int i=0; i<numsSize; i++) {
int count = countLetter(nums, numsSize, nums[i]);
if (count == 1)
return nums[i];
}
return 0;
}
int main()
{
int nums[] = {5, 8, 5, 6, 8, 7, 7};
int number = singleNumber(nums, 7);
printf("The single number is %d.\n", number);
}
结果:
系统虽然接受了这个程序,但是运行时间长达400ms,排名也十分靠后。
很明显是时间上吃了亏。在这个程序中,singleNumber函数中有一个for循环,在这个for循环中调用了countLetter函数,而countLetter函数中也有一个for循环,这样时间复杂度就达到了O(n2),这样的时间复杂度太高了。
所以要想改进的话就要从时间复杂度来入手了
改进思路:
用异或的性质。
异或有交换性,还有一个很有意思的性质,a^b^b=a,即数a两次异或同一个数b(a=a^b^b)仍然为原值a。又如:a^b^a^c^b^c^d=d。
令k等于数组中任意一个数字,并与剩余元素进行异或运算,最后结果就是那个single number。
#include <stdio.h>
int singleNumber(int* nums, int numsSize) {
int k = nums[0];
for (int i=1; i<numsSize; i++) {
k = (k ^ nums[i]);
}
return k;
}
int main()
{
int nums[] = {5, 6, 5, 6, 8, 7, 7};
int number = singleNumber(nums, 7);
printf("The single number is %d.\n", number);
}
结果:
这次运行时间为4ms,相比400ms效率不知道高到哪里去了,排名自然也非常靠前。
异或还有一些其他有意思的性质,比如可以在不引入临时变量的情况下交换两个变量的值等等。
a=10100001, b=00000110
a=a^b; //a=10100111
b=b^a; //b=10100001
a=a^b; //a=00000110
参考:一起玩算法02
推荐一位干货up主:正月点灯笼
少一些功利主义的追求,多一些不为什么的坚持