题目
链接:leetcode链接
思路分析(一题多解)
思路一:高斯求和公式
利用高斯求和公式求出0~n的和,然后减去nums数组中的每一个数,最后的结果就是缺失的数字
时间复杂度,O(N)
过于简单,就不写代码了
思路二:差分
求出每一个元素与前一个元素的差,然后哦遍历这个差,当发现差值不等于1的时候,就返回该位置的值即可。
细节:要特殊处理一下缺失0的情况。
时间复杂度,O(N)
int takeAttendance(vector<int>& records) {
int n = records.size();
if(records[0] != 0)return 0;
vector<int> dp(n);
int i = 0;
for( i = 1;i < n;i++)
{
dp[i] = records[i] - records[i - 1];
if(dp[i] != 1)
break;
}
return i;
}
思路三:位运算
采用按位异或的操作,相同为0,不同为1
将0~n的所有数字均与nums中的数字按位异或一下,最后的结果就是缺失的数字
时间复杂度O(N)
int takeAttendance(vector<int>& records) {
int tmp = 0;
int n = records.size();
for(int i = 1;i <= n;++i)
{
tmp^=i;
}
for(int i = 0;i < records.size();++i)
{
tmp^=records[i];
}
return tmp;
}
思路四:二分算法
注意了,这是因为题目特殊,题目是有序的情况下,才能存在这种二段性,否则要先排序
如何寻找这个二段性?
我们可以发现,当有序的序列缺失了一个元素之后
在缺失元素之前的每一个元素都和下标相等,
而缺失元素之后的每一个元素都比下标大。
根据这个二段性,我们就可以使用二分算法了。
还是寻找左边界的二分。
细节:
while(left < right) // 不能取等,否则会死循环
mid = left + (right - left) / 2;
left = mid + 1;
right = mid;
如果缺失的元素是最后一个数据的话,需要特判
时间复杂度O(logN)
int takeAttendance(vector<int>& records) {
int left = 0,right = records.size() - 1;
while(left < right)
{
int mid = left + (right - left) / 2;
if(records[mid] == mid) left = mid + 1;
else right = mid;
}
if(left == records[left]) return left + 1;
return left;
}