简单
两数之和
描述
给出一个整型数组 numbers 和一个目标值 target,请在数组中找出两个加起来等于目标值的数的下标,返回的下标按升序排列。
(注:返回的数组下标从1开始算起,保证target一定可以由数组里面2个数字相加得到)
解题思路:
- 两个for循环(缺点:超时)
- 哈希表<取值, 下标>
class Solution {
public:
/**
*
* @param numbers int整型vector
* @param target int整型
* @return int整型vector
*/
vector<int> twoSum(vector<int>& numbers, int target) {
// write code here
vector<int> res;
int n = numbers.size();
if(n==0)
return res;
unordered_map<int, int> haxi;//定义哈希表,<取值,下标>
for(int i=0; i<n; i++){
if(haxi.count(target-numbers[i])){ //找到执行,没找到不执行
res.push_back(haxi[target-numbers[i]]+1);
res.push_back(i+1);
break;
}else{
//将未找到的值插入哈希表中
haxi[numbers[i]] = i;
}
}
return res;
}
// for(int i=0; i<numbers.size()-1; i++){
// for(int j=i+1; j<numbers.size(); j++){
// if(numbers[i] + numbers[j] == target){
// res.push_back(i+1);
// res.push_back(j+1);
// return res;
// }
// }
// }
// return res;
// }
};
合并两个有序的数组
描述
给出一个有序的整数数组 A 和有序的整数数组 B ,请将数组 B 合并到数组 A 中,变成一个有序的升序数组
注意
1.保证 A 数组有足够的空间存放 B 数组的元素, A 和 B 中初始的元素数目分别为 m 和 n,A的数组空间大小为 m+n
2.不要返回合并的数组,将数组 B 的数据合并到 A 里面就好了,且后台会自动将合并后的数组 A 的内容打印出来,所以也不需要自己打印
3. A 数组在[0,m-1]的范围也是有序的
思路:
- step 1:使用三个指针,i指向数组A的最大元素,j指向数组B的最大元素,k指向数组A空间的结尾处。
- step 2:从两个数组最大的元素开始遍历,直到某一个结束,每次取出较大的一个值放入数组A空间的最后,然后指针一次往前。
- step 3:如果数组B先遍历结束,数组A前半部分已经存在了,不用管;但是如果数组A先遍历结束,则需要把数组B剩余的前半部分依次逆序加入数组A前半部分,类似归并排序最后的步骤。
class Solution {
public:
void merge(int A[], int m, int B[], int n) {
int i = m-1, j = n-1, k = m+n-1;
while(i>=0 && j>=0){
if(A[i] > B[j])
A[k--] = A[i--];
else
A[k--] = B[j--];
}
if(i < 0){
while(j>=0)
A[k--] = B[j--];
}
}
};
螺旋矩阵
描述
给定一个m x n大小的矩阵(m行,n列),按螺旋的顺序返回矩阵中的所有元素。
解题:
- 四个边界—上边界、下边界、左边界、右边界
- 直到边界重合
class Solution {
public:
vector<int> spiralOrder(vector<vector<int> > &matrix) {
vector<int> res;
int n = matrix.size();
if(n == 0)
return res;
//左边界、右边界、上边界、下边界
int left = 0;
int right = matrix[0].size() -1;
int top = 0;
int down = n-1;
//直到边界重合
while(left <= right && top <= down){
//上边界从左到右
for(int i=left; i<=right; i++)
res.push_back(matrix[top][i]);
top++;
if(top>down)
break;
//右边界从上到下
for(int i=top; i<= down; i++)
res.push_back(matrix[i][right]);
right--;
if(left>right)
break;
//下边界从右到左
for(int i=right; i>=left; i--)
res.push_back(matrix[down][i]);
down--;
if(top>down)
break;
//左边界从下到上
for(int i=down; i>=top; i--)
res.push_back(matrix[i][left]);
left++;
if(left>right)
break;
}
return res;
}
};
斐波那契数列
递归
class Solution {
public:
int Fibonacci(int n) {
if(n == 1 || n== 2)
return 1;
return Fibonacci(n-1) + Fibonacci(n-2);
}
};
中等
最长无重复子数组
描述
给定一个长度为n的数组arr,返回arr的最长无重复元素子数组的长度,无重复指的是所有数字都不相同。
子数组是连续的,比如[1,3,5,7,9]的子数组有[1,3],[3,5,7]等等,但是[1,3,7]不是子数组
解题思路
- step 1:构建一个哈希表,用于统计数组元素出现的次数。
- step 2:窗口左右界都从数组首部开始,每次窗口优先右移右界,并统计进入窗口的元素的出现频率。
- step 3:一旦右界元素出现频率大于1,就需要右移左界直到窗口内不再重复,将左边的元素移除窗口的时候同时需要将它在哈希表中的频率减1,保证哈希表中的频率都是窗口内的频率。
- step 4:每轮循环,维护窗口长度最大值。
class Solution {
public:
/**
*
* @param arr int整型vector the array
* @return int整型
*/
int maxLength(vector<int>& arr) {
// write code here
unordered_map<int, int> mp;
int res = 0;
int j = 0;
for(int i=0; i<arr.size(); i++){
//右移进入哈希表统计出现次数
mp[arr[i]]++;
//出现次数大于1,有重复
while(mp[arr[i]] > 1)
mp[arr[j++]]--;
res = max(res, i-j+1);
}
return res;
}
};
三数之和
描述
给出一个有n个元素的数组S,S中是否有元素a,b,c满足a+b+c=0?找出数组S中所有满足条件的三元组。
数据范围:0≤n≤3000,数组中各个元素值满足 ∣val∣≤100
空间复杂度:O(n^2),时间复杂度 O(n^2)
注意:
三元组(a、b、c)中的元素可以按任意顺序排列。
解集中不能包含重复的三元组。
输入:[-10,0,10,20,-10,-40]
返回值:[[-10,-10,20],[-10,0,10]]
思路:
- 如果找到了某个数a,要找到与之对应的另外两个数,三数之和为0,等价于只要找到另外两个数之和为−a
具体做法:
- step 1:排除边界特殊情况。
- step 2:既然三元组内部要求非降序排列,那我们先得把这个无序的数组搞有序了,使用sort函数优先对其排序。
- step 3:得到有序数组后,遍历该数组,对于每个遍历到的元素假设它是三元组中最小的一个,那么另外两个一定在后面。
- step 4:需要三个数相加为0,则另外两个数相加应该为上述第一个数的相反数,我们可以利用双指针在剩余的子数组中找有没有这样的数对。双指针指向剩余子数组的首尾,如果二者相加为目标值,那么可以记录,而且二者中间的数字相加可能还会有。
- step 5:如果二者相加大于目标值,说明右指针太大了,那就将其左移缩小,相反如果二者相加小于目标值,说明左指针太小了,将其右移扩大,直到两指针相遇,剩余子数组找完了。
注:对于三个数字都要判断是否相邻有重复的情况,要去重。
class Solution {
public:
static bool cmp(int x, int y){
return x<y;
}
vector<vector<int> > threeSum(vector<int> &num) {
vector<vector<int>> res;
int n = num.size();
if(n < 3)
return res;
//对num排序
sort(num.begin(), num.end(),cmp);
for(int i=0; i<n-2; i++){
if(i != 0 && num[i] == num[i-1])
continue;
int left = i+1;
int right = n-1;
int target = -num[i]; //两数相加为-num[i]
while(left < right){
if(num[left] + num[right] == target){
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;
}
};