leetcode解题系列(八)
继续学习!
136.只出现一次的数字
这是一道看上去非常简单的题目,如果可以使用count函数就可以直接遍历一遍所有元素然后当值为1时直接返回…当然这种暴力解法只适合我这种无脑新手,代码是异常简单,如下:
class Solution {
public:
int singleNumber(vector<int>& nums) {
for(int i=0;i<nums.size();i++){
if(count(nums.begin(),nums.end(),nums[i])==1){
return nums[i];
}
}
return 0;
}
};
时间复杂度虽然是O(n),也没用到额外的空间,但是实际非常慢;尝试用新的方法:
想的第二个方法就是先用一个哈希表存储次数信息,然后遍历整个数组,当第一次出现时加上这个数,第二次出现时减去这个数,最后的答案一定会是只出现了一次的那个数:
代码如下:
class Solution {
public:
int singleNumber(vector<int>& nums) {
unordered_map<int,int> cnt;
int res=0;
for(int num:nums){
cnt[num]++;
if(cnt[num]==1)res+=num;
else res-=num;
}
return res;
}
};
速度上确实有了显著的提升,不过还是不够;看一下题解吧:
没想到,这里的配对的这个功能是异或 的这个位运算得到的,异或的性质刚刚可以满足这样的需求:
三行代码就可以轻松搞定:
class Solution {
public:
int singleNumber(vector<int>& nums) {
int ret = 0;
for (auto e: nums) ret ^= e;
return ret;
}
};
时间也是非常优秀,可以当作一个小trick记住吧
389.找不同
题目描述:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KuBtyQmX-1620810212967)(C:\Users\thinkpad\AppData\Roaming\Typora\typora-user-images\image-20210512144552496.png)]
第一反应就想到了上面的异或操作:
class Solution {
public:
char findTheDifference(string s, string t) {
int res=0;
if(s.length()==0){
return t[0];
}
for(int i=0;i<s.length();i++){
res^=int(s[i]);
res^=int(t[i]);
}
res^=int(t[t.length()-1]);
return char(res);
}
};
一次写对,非常优秀;
这个方法确实非常好用;
这道题还有个非常简单的方法就是用t字符串的所有值加起来以后再减去s的所有值,这样最后的结果一定就是t多出来的字符:
class Solution {
public:
char findTheDifference(string s, string t) {
int res=0;
for(int i=0;i<s.length();i++){
res+=int(t[i]);
res-=int(s[i]);
}
res+=int(t[t.length()-1]);
return char(res);
}
};
下一题:
剑指53 丢失的数字
题目描述:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fnSO8ZJe-1620810212971)(C:\Users\thinkpad\AppData\Roaming\Typora\typora-user-images\image-20210512145321909.png)]
第一时间的想法就是直接将所有数字加和起来,然后跟等差数列的和做一个差,就能轻松算出来结果,代码如下:
class Solution {
public:
int missingNumber(vector<int>& nums) {
int add=0;
int n=nums.size();
for(int num:nums){
add+=num;
}
return ((1+n)*n/2)-add;
}
};
比较简单,其实对于升序排列的也可以用更简单的方法:内容和序号不符合时直接return:
class Solution {
public:
int missingNumber(vector<int>& nums) {
for(int i=0;i<nums.size();i++){
if(nums[i]!=i)return i;
}
return nums.size();
}
};
突然感觉有点侮辱智商!
但其实这样做还是不够快,因为当元素比较靠尾部时需要比较长时间才可以求出,所以这里需要用到二分法:
但是题解中还有种好的方法:二分法:思路也是比较简单,因为每次只要知道中间元素的值就可以知道确实的元素在中间元素的左边还是右边:
class Solution {
public:
int missingNumber(vector<int>& nums) {
int start=0;
int end=nums.size()-1;
int mid=(start+end)/2;
if(nums.size()==1){
if(nums[0]==0)return 1;
else return 0;
}
while((start+1)!=end){
if(nums[mid]!=mid){//缺失数字在左边
end=mid;
mid=(start+end)/2;
}else{
start=mid;
mid=(start+end)/2;
}
}
if(nums[mid]!=mid)return mid;
else if(nums[end]!=end) return end;
else return end+1;
}
};
这代码写得就很牵强。。。
461、汉明距离
题目描述:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-scFSp3SV-1620810212975)(C:\Users\thinkpad\AppData\Roaming\Typora\typora-user-images\image-20210512160608578.png)]
主要是位运算的一些知识要知道,首先用异或就可以轻松求出不相同的位,然后用&1一位一位去加和就可以得到:
class Solution {
public:
int hammingDistance(int x, int y) {
int num = x^y;
int res = 0;
while(num > 0){
res += (num & 1);
num = num >> 1;
}
return res;
};
};
没什么问题
249有效的字母异位词
题目描述:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qOVUqYLN-1620810212976)(C:\Users\thinkpad\AppData\Roaming\Typora\typora-user-images\image-20210512161849001.png)]
简单的方法:
先排序,再比较:
class Solution {
public:
bool isAnagram(string s, string t) {
if(s.size()!=t.size())return false;
sort(s.begin(),s.end());
sort(t.begin(),t.end());
for(int i=0;i<s.size();i++){
if(s[i]!=t[i])return false;
}
return true;
}
};
最简单的思路,至少保证结果是对的。
也可以使用哈希表的方法,反正都是差不多的。
349、两个数组的交集
题目描述:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4m4THF11-1620810212978)(C:\Users\thinkpad\AppData\Roaming\Typora\typora-user-images\image-20210512163459116.png)]
第一反应就是直接遍历一个数组时,直接在另一个数组种搜索是否存在,若是,则加入res:
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
vector<int>res;
for(int i=0;i<nums1.size();i++){
if(count(nums2.begin(),nums2.end(),nums1[i])>0&&count(res.begin(),res.end(),nums1[i])==0)
res.push_back(nums1[i]);
}
for(int i=0;i<nums2.size();i++){
if(count(nums1.begin(),nums1.end(),nums2[i])>0&&count(res.begin(),res.end(),nums2[i])==0)
res.push_back(nums2[i]);
}
return res;
}
};
可以通过测试,但一定不是最优解;
还想到一种,先排序,然后设置双指针搜索:
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
sort(nums1.begin(), nums1.end());
sort(nums2.begin(), nums2.end());
int length1 = nums1.size(), length2 = nums2.size();
int index1 = 0, index2 = 0;
vector<int> intersection;
while (index1 < length1 && index2 < length2) {
int num1 = nums1[index1], num2 = nums2[index2];
if (num1 == num2) {
// 保证加入元素的唯一性
if (!intersection.size() || num1 != intersection.back()) {
intersection.push_back(num1);
}
index1++;
index2++;
} else if (num1 < num2) {
index1++;
} else {
index2++;
}
}
return intersection;
}
};