如果题目已知的arr[i]的取值范围没有要求
题目:只出现一次的数字链接
思路:
x^0=x
x^x=0
代码:
class Solution {
public:
int singleNumber(vector<int>& nums)
{
int ret=0;
for(int value:nums)
{
ret=ret^value;
}
return ret;
}
};
如果题目已知的arr[i]的取值范围有取值范围,并且明显有数组中数字与下标有一一对应的性质
题目:剑指 Offer 03. 数组中重复的数字链接
思路:
很明显, nums.size()=n 并且里面的每个数字在 0~n-1 之间,将每个没有归位的元素归位,如果发现待归位元素的待交换的位置是存的相同的值,也就是重复了
if(nums[i]==nums[nums[i]])
{
return nums[i];
}
每次将元素归位,时间复杂度是o(n) (for中虽有while循环,但是代码运行时,while并不是每次都执行,最多执行的总次数是o(n).)
代码:
class Solution {
public:
int findRepeatNumber(vector<int>& nums)
{
//这题并没有要求求出所有重复的数字
for(int i=0;i<nums.size();i++)
{
while(nums[i]!=i)
{
if(nums[i]==nums[nums[i]])
{
return nums[i];
}
swap(nums[i],nums[nums[i]]);
}
cout<<"i="<<i<<endl;
}
return 0;
}
};
思路:
这题和上一题基本一样,这题将所有的重复元素算出,
需要注意的是,由于需要求出所有重复的元素,并且重复的元素只能加入一次,
因此我们需要
if (nums[i]==-1) break;
if(nums[i]==nums[nums[i]-1])
{
ret_v.push_back(nums[i]);
nums[i]=-1;
break;
}
下面我们来分析下面代码的时间复杂度
将元素归位时间复杂度是o(n)(for中虽有while循环,但是代码运行时,while并不是每次都执行,最多执行的总次数是o(n).)
题目中说不需要额外空间,也就是o(1)空间,但是返回值又是vector 并且在代码中我们会发现申请了空间,题目的意思其实是 我们申请的空间只能用来存结果,这样就算做没有使用额外的空间
代码:
class Solution
{
//首先我们需要知道 1 ≤ a[i] ≤ n 就一直在暗示我们 元素和下标一一对应的关系,因此。我们需要将元素放在正确的位置上面就可以了
public:
vector<int> findDuplicates(vector<int>& nums)
{
vector<int> ret_v;
for(int i=0;i<nums.size();i++)
{
while((nums[i]-1)!=i)//这种题对应的的标记一定不能弄混
{
if (nums[i]==-1) break;
if(nums[i]==nums[nums[i]-1])
{
//cout<<"nums[i]="<<nums[i]<<endl;
ret_v.push_back(nums[i]);
nums[i]=-1;
break;
}else
{
swap(nums[i],nums[nums[i]-1]);
}
}
}
return ret_v;
}
};
思路:
这题就是将上一题变了一点,将元素归位后将 然后将numbers进行遍历,元素值是-1(代表重复,或者没有这个位置本该对应的元素)的index+1 存入vector 中。
代码:
class Solution {
public:
vector<int> findDisappearedNumbers(vector<int>& nums)
{
vector<int> ret_v;
for(int i=0;i<nums.size();i++)
{
while((nums[i]-1)!=i)//这种题对应的的标记一定不能弄混
{
if (nums[i]==-1) break;
if(nums[i]==nums[nums[i]-1])
{
nums[i]=-1;
break;
}else
{
swap(nums[i],nums[nums[i]-1]);
}
}
}
for(int i=0;i<nums.size();i++)
{
if(nums[i]==-1) ret_v.push_back(i+1);
}
return ret_v;
}
};