BM50 两数之和
简单 通过率:37.01% 时间限制:1秒 空间限制:256M
知识点数组哈希
描述
给出一个整型数组 numbers 和一个目标值 target,请在数组中找出两个加起来等于目标值的数的下标,返回的下标按升序排列。
(注:返回的数组下标从1开始算起,保证target一定可以由数组里面2个数字相加得到)
数据范围:2≤len(numbers)≤105,−10≤numbersi≤109,0≤target≤109
要求:空间复杂度 O(n),时间复杂度 O(nlogn)
示例1
输入:
[3,2,4],6
返回值:
[2,3]
说明:
因为 2+4=6 ,而 2的下标为2 , 4的下标为3 ,又因为 下标2 < 下标3 ,所以返回[2,3]
示例2
输入:
[20,70,110,150],90
返回值:
[1,2]
说明:
20+70=90
我们能想到最直观的解法,可能就是两层遍历,将数组所有的二元组合枚举一遍,看看是否是和为目标值,但是这样太费时间了,既然加法这么复杂,我们是不是可以尝试一下减法:对于数组中出现的一个数a,如果目标值减去a的值已经出现过了,那这不就是我们要找的一对元组吗?这种时候,快速找到已经出现过的某个值,可以考虑使用哈希表快速检验某个元素是否出现过这一功能。
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
vector<int> res;
//创建哈希表,key是值、value是下标
unordered_map<int, int> m;
//在哈希表中查找target-numbers[i]
for(int i = 0; i < numbers.size(); i++){
int temp = target - numbers[i];
//若是没找到,将此信息计入哈希表
if (m.find(temp) == m.end()) {
m[numbers[i]] = i;
} else {
//哈希表中记录的是之前的数字,之前的数字的索引比当前数字小
res.push_back(m[temp] + 1);
res.push_back(i + 1);
break;
}
}
return res;
}
};
BM54 三数之和
中等 通过率:24.88% 时间限制:1秒 空间限制:256M
知识点数组双指针排序
描述
给出一个有n个元素的数组S,S中是否有元素a,b,c满足a+b+c=0?找出数组S中所有满足条件的三元组。
数据范围:0≤n≤1000,数组中各个元素值满足 ∣val∣≤100
空间复杂度:O(n2),时间复杂度 O(n2)
注意:
三元组(a、b、c)中的元素必须按非降序排列。(即a≤b≤c)
解集中不能包含重复的三元组。
例如,给定的数组 S = {-10 0 10 20 -10 -40},解集为(-10, -10, 20),(-10, 0, 10)
示例1
输入:
[0]
返回值:
[]
示例2
输入:
[-2,0,1,1,2]
返回值:
[[-2,0,2],[-2,1,1]]
示例3
输入:
[-10,0,10,20,-10,-40]
返回值:
[[-10,-10,20],[-10,0,10]]
class Solution {
public:
vector<vector<int> > threeSum(vector<int> &num) {
vector<vector<int> > res;
//int n = num.size();
if(num.size() < 3) {
return res;
}
sort(num.begin(), num.end());
for(int i = 0; i < num.size() - 2; i++){
if(i != 0 && num[i] == num[i - 1]) {
continue;
}
//区间起始下标
int left = i + 1;
int right = num.size() - 1;
//设置当前数的负值为目标
int target = -num[i];
while (left < right) {
if (num[left] + num[right] == target) {
//双指针指向的二值相加为目标,则可以与num[i]组成0
res.push_back({num[i], num[left], num[right]});
while (left + 1 < right && num[left] == num[left + 1]) {
//去重
left++;
}
while (right - 1 > left && num[right] == num[right - 1]){
//去重
right--;
}
//双指针向中间收缩
left++;
right--;
} else if(num[left] + num[right] > target) {
//双指针指向的二值相加大于目标,右指针向左
right--;
} else {
//双指针指向的二值相加小于目标,左指针向右
left++;
}
}
}
return res;
}
};
BM53 缺失的第一个正整数
题目
题解(110)
讨论(100)
排行
面经new
中等 通过率:39.17% 时间限制:1秒 空间限制:256M
知识点
数组
哈希
描述
给定一个无重复元素的整数数组nums,请你找出其中没有出现的最小的正整数
进阶: 空间复杂度 O(1)O(1),时间复杂度 O(n)O(n)
数据范围:
-2^{31}\le nums[i] \le 2^{31}-1−2
31
≤nums[i]≤2
31
−1
0\le len(nums)\le5*10^50≤len(nums)≤5∗10
5
示例1
输入:
[1,0,2]
复制
返回值:
3
复制
示例2
输入:
[-2,3,4,1,5]
复制
返回值:
2
复制
示例3
输入:
[4,5,6,8,9]
复制
返回值:
1
复制
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param nums int整型vector
* @return int整型
*/
int minNumberDisappeared(vector<int>& nums) {
unordered_set<int> s;
for (int i = 0; i < nums.size(); ++i) {
s.insert(nums[i]);
}
int num = 1;
while (s.find(num) != s.end()) {
num++;
}
return num;
}
};
JZ39 数组中出现次数超过一半的数字
简单 通过率:33.06% 时间限制:1秒 空间限制:256M
知识点哈希数组
描述
给一个长度为 n 的数组,数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
例如输入一个长度为9的数组[1,2,3,2,2,2,5,4,2]。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。
数据范围:n≤50000,数组中元素的值 0≤val≤10000
要求:空间复杂度:O(1),时间复杂度 O(n)
输入描述:
保证数组输入非空,且保证有解
示例1
输入:
[1,2,3,2,2,2,5,4,2]
返回值:
2
示例2
输入:
[3,3,3,3,2,2,2]
返回值:
3
示例3
输入:
[1]
返回值:
1
要求:空间复杂度:O(n),时间复杂度 O(n)
方法:哈希表
class Solution {
public:
int MoreThanHalfNum_Solution(vector<int> numbers) {
//无序哈希表统计每个数字出现的次数
unordered_map<int, int> m;
//遍历数组
for(int i = 0; i < numbers.size(); i++){
//哈希表中相应数字的个数加1
m[numbers[i]]++;
//当某个数字的个数大于数组长度一半,即可返回
if(m[numbers[i]] > numbers.size() / 2)
return numbers[i];
}
return 0;
}
};
要求:空间复杂度:O(1),时间复杂度 O(n)
方法:跟踪记忆法
vector vec{2, 2, 2, 2, 2, 3, 5, 7, 8};
下标 0 1 2 3 4 5 6 7 8
数字 2, 2, 2, 2, 2, 3, 5, 7, 8
count 1 2 3 4 5 4 3 2 1
num 2 2 2 2 2 2 2 2 2
vector vec{1, 2, 3, 2, 5, 2, 7, 2, 2};
下标 0 1 2 3 4 5 6 7 8
数字 1, 2, 3, 2, 5, 2, 7, 2, 2
count 1 0 1 0 1 0 1 0 1
num 1 1 3 3 5 5 7 7 2
class Solution {
public:
int MoreThanHalfNum_Solution(vector<int> numbers) {
if (numbers.size() == 1) {
return numbers[0];
}
int num = numbers[0];
int count = 0;
for (int i = 0; i < numbers.size(); i++) {
if (count == 0 || num == numbers[i]) {
count++;
num = numbers[i];
} else {
count--;
}
}
return num;
}
};
BM52 数组中只出现一次的两个数字
题目
题解(184)
讨论(205)
排行
面经new
中等 通过率:55.22% 时间限制:1秒 空间限制:256M
知识点
位运算
哈希
描述
一个整型数组里除了两个数字只出现一次,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
数据范围:数组长度 2\le n \le 10002≤n≤1000,数组中每个数的大小 0 < val \le 10000000
提示:输出时按非降序排列。
示例1
输入:
[1,4,1,6]
复制
返回值:
[4,6]
复制
说明:
返回的结果中较小的数排在前面
示例2
输入:
[1,2,3,3,2,9]
复制
返回值:
[1,9]
复制
要求:空间复杂度 O(n),时间复杂度 O(n)
方法:哈希表
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param array int整型vector
* @return int整型vector
*/
vector<int> FindNumsAppearOnce(vector<int>& array) {
unordered_map<int, int> m;
vector<int> res;
for (int i = 0; i < array.size(); ++i) {
m[array[i]]++;
}
for (int i = 0; i < array.size(); ++i) {
if (m[array[i]] == 1) {
res.push_back(array[i]);
}
}
sort(res.begin(), res.end());
return res;
}
};
要求:空间复杂度 O(1),时间复杂度 O(n)
方法:异或
/*
1.异或运算满足交换律:a ^ b 等于 b ^ a
2.相同的数字 异或 结果为0:a ^ a 等于0,b ^ b 等于0
3.任何数字 与 0 异或 不变:a ^ 0 等于a,b ^ 0 等于b
4.位运算符的优先级低于 == 运算符, if ( (array[i] & num) == 0) 一定要加上括号
5.采用移位运算符:左移一位相当于 乘以2;右移一位相当于除以2
6.借用res数组。
*/
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param array int整型vector
* @return int整型vector
*/
vector<int> FindNumsAppearOnce(vector<int>& array) {
vector<int> res(2, 0);
if (array.empty()) {
return res;
}
int diff = 0;
for (int i = 0; i < array.size(); i++) {
diff ^= array[i];
}
// diff的二进制数据中至少有一位是1
// 从最低位开始寻找,找到第一个为1的位置
// 通过这个位置是0和1,区分这两个数字
int num = 1;
while ( (diff & num) == 0) {
num <<= 1;
}
for (int i = 0; i < array.size(); i++) {
if ( (array[i] & num) == 0) {
res[0] ^= array[i];
} else {
res[1] ^= array[i];
}
}
if (res[0] < res[1]) {
return res;
} else {
return {res[1], res[0]};
}
}
};