昨天生日,停更了一天,今天都补上。
这道题目最先想到的是从1开始遍历进行判断,但是显然会很复杂,所以要想到使用动态规划,去牺牲空间记录前面数的状态。
总的来说我们只需判断两个部分,i % 10是否为有效,i /10 是否有效,这样递推下去。
使用helper数组记录状态,起始初始化为0,坏数为1,好数为2,如下所示:
class Solution {
public:
int rotatedDigits(int n) {
vector<int>helper(n+1,0);
int count=0;
for(int i=1;i<=n;i++)
{
if(i==3 || i==4 || i==7 || helper[i%10]==1 || helper[i/10]==1)
{
helper[i]=1;
}
else if( i==2 || i==5 || i==6 || i==9 || helper[i%10]==2 || helper[i/10]==2)
{
helper[i]=2;
count++;
}
}
return count;
}
};
对于这道题使用数组或者哈希表去记录出现的数字是最好的,但是复杂度的要求不能让我们这么做。
因为从1 到n 的数字少了两个,然后其余数字出现一次,所以一共有 n-2 个数字,那么我们将n个数字加在n-2个数字之后,这样的话有2n-2个数,期中有n-2个数字出现了两次,如果我们将他们异或起来,最后会得到 x=x1 ^ x2;
然后我们通过x^-x得到x的最低位1,那么x1 和 x2总有这位的不同,一个为1一个为0。我们将该位不同的数分为两组,再去异或2n-2个数,那么两类分别异或的结果为所求。
class Solution {
public:
vector<int> missingTwo(vector<int>& nums) {
int xorsum = 0;
int n = nums.size() + 2;
for (int num : nums) {
xorsum ^= num;
}
for (int i = 1; i <= n; i++) {
xorsum ^= i;
}
int lsb = (xorsum == INT_MIN ? xorsum : xorsum & (-xorsum));
int type1 = 0, type2 = 0;
for (int num : nums) {
if (num & lsb) {
type1 ^= num;
} else {
type2 ^= num;
}
}
for (int i = 1; i <= n; i++) {
if (i & lsb) {
type1 ^= i;
} else {
type2 ^= i;
}
}
return {type1, type2};
}
};