给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
解法1:位异或:
class Solution {
public:
int singleNumber(vector<int>& nums) {
int ret = 0;
for (auto e: nums) ret ^= e;//这里运算符的逻辑没太懂
return ret;
}
};
解法2 :用容器定义的哈希表来做。
空间复杂度O(n)
class Solution {
public:
int singleNumber(vector<int>& nums) {
vector<int>tmpnums(10,0);
for (int val : nums)
{
tmpnums.at(val) += 1;
}
for (int i=0;i<10;i++)
{
if (tmpnums.at(i) == 1)
{
return i;
}
}
exit(0);
}
};
这里有个问题就是第一,如果不初始化自定义的容器tmpnums,那么leecode在测试时会出现越界。在一个基于范围的for不能返回下标,所以我们只能用普通的for来返回哈希的下标。但是还有一个更重要的问题,容器的下标都是从零开始,测试用例给个负数就没法办了。所以这个代码还是非常受局限的。编译器给的哈希表我也不会用。。。。。。。
剑指offer:不用加减乘除做加法
class Solution {
public:
int add(int a, int b)
{
int carry;
while(b)
{
carry=a&b;//进位
a=a^b;//先求本位
b=(unsigned)carry<<1;
}
return a;
}
};
这道题想要做出来必须要知道的是cpu累加器的原理(半累加器:求进位用与(&)加异或(^),求本位用异或)).
用循环来模拟全累加器。每一个循环都是单个位的累加计算。
例子(15和8)
第一次:(1111的最后一位)1 0(1000的最后一位) 的位累加 :
进位 0(1&0得0 再进位还是0;就不进位了)
本位1 (1^0得1) --> 所以本位(结果的最后一位填1)
第二次(同理) 1 和0
进位 为0
本位为1
第三次 1 和0
进位 为0
本位为1
第四次 1和1
进位为1 (本位求完后再进位 )
本位为0 所以结果的正数第二位,也就是15+8的23(10111)的左数第二位。
进位的1与0(此位没数自动设为0)异或得1 所以 左数第一位是1.
最后的结果为(1111+1000)=(10111)=23
同构字符串
给定两个字符串 s 和 t ,判断它们是否是同构的。
如果 s 中的字符可以按某种映射关系替换得到 t ,那么这两个字符串是同构的。
每个出现的字符都应当映射到另一个字符,同时不改变字符的顺序。不同字符不能映射到同一个字符上,相同字符只能映射到同一个字符上,字符可以映射到自己本身。
数学上的映射关系:
class Solution {
public:
bool isIsomorphic(string s, string t) {
unordered_map<char,char>s2t,t2s;//定义两个哈希表
for(int i=0;i<s.size();i++)
{
char a=s[i],b=t[i]; //把键值对的两个值分别存起来 方便coding
if((s2t.find(a)!=s2t.end()&&b!=s2t[a])||(t2s.find(b)!=t2s.end()&&a!=t2s[b]))
// if 语句||前面,&&前半段是判断是否找到了这个这个值,如果已经找到这个值,说明有这个映射的键值对,&&后半段是判断已经有的键值对映射在哈希表里的值与新循环的i对应 的即将放入哈希表中的b比较,不相同则说明不是一一对应的映射关系,则返回false;
// 因为映射是双向的,所以也得判断相反方向是否出现一不对一的情况。
{
return false;
}
s2t[a]=b;//把a映射的b存在2s2t中
t2s[b]=a;
}
return true;
}
};