持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第30天,点击查看活动详情
448. 找到所有数组中消失的数字
思路
(数组) O(n)
用负号识别当前数是否用过
1、遍历每个元素,对索引进行标记,将对应索引位置的值变为负数;
2、遍历下索引,看看哪些索引位置上的数不是负数的,位置上不是负数的索引,对应的元素就是不存在的。
时间复杂度分析: 遍历两次数组,故时间复杂度为O(n)。
c++代码
class Solution {
public:
vector<int> findDisappearedNumbers(vector<int>& nums) {
vector<int> res;
for(int x : nums){
x = abs(x);
if(nums[x - 1] > 0) nums[x - 1] *= -1;
}
for(int i = 0; i < nums.size(); i++){
if(nums[i] > 0)
res.push_back(i + 1);
}
return res;
}
};
461. 汉明距离
思路
(位运算) O(logx)
1、先将x
和y
作异或运算,异或运算之后,相同位为0
,不同位为1
。
2、统计x ^ y
中1
的个数。
时间复杂度分析: 异或的时间复杂度为 O(1),统计二进制位 1 的个数时间复杂度为 O(logx),故总时间复杂度为 O(logx)。
c++代码
class Solution {
public:
int hammingDistance(int x, int y) {
int n = x ^ y; //相同位为0,不同位
int res = 0;
while(n){
n -= n & -n; //lowbit
res++;
}
return res;
}
};
494. 目标和
思路
(动态规划, 01背包) O(n * s)
状态表示: f[i][j]
表示从nums
数组的前i
个数中选,且总和是j
的方案数。
状态计算:
对于最后一个选择的数字nums[i]
,我们可以取正也可以取负,因此有两种方案:
- 取正,则
f[i][j] = f[i - 1][j - nums[i]]
; - 取负,则
f[i][j] = f[i - 1][j + nums[i]]
;
两种方案数相加,状态转移方程为 f[i][j] = f[i - 1][j - nums[i]] + f[i - 1][j + nums[i]]
。
实现细节:
由于-1000 <= target <= 1000
,因此j
可能会取到负数,为了避免负数,在这里我们需要加上偏移量Offset
。
初始化: f[0][0] = 1
,从前0
个数中选,和为0
的方案数为1
。
时间复杂度分析: 状态数量为O(n * s),状态计算为O(1),故总的时间复杂度为O(n * s)。
c++代码
class Solution {
public:
// 动态规划
int findTargetSumWays(vector<int>& nums, int target) {
int n = nums.size(), Offset = 1000; // offset为偏移量
vector<vector<int>> f(n + 1, vector<int>(2000 + 10));
f[0][Offset] = 1; //对应f[0][0] = 1, 前0个数,和为0的方案数为1
for(int i = 1; i <= n; i++){
for(int j = - 1000; j <= 1000; j++){
if(j - nums[i - 1] >= -1000)
f[i][j + Offset] += f[i - 1][j + Offset - nums[i - 1]];
if(j + nums[i - 1] <= 1000)
f[i][j + Offset] += f[i - 1][j + Offset + nums[i - 1]];
}
}
return f[n][target + Offset];
}
};