leetcode-数组操作
238. 除自身以外的数组乘积
第一眼就是求总乘积,然后除自身,但题目要求不能用除法;
除自身以外,就是左右两边子数组,那不就是一个前缀乘积*后缀乘积吗,逻辑就出来,前缀i-1✖后缀i+1,就好了,不过注意两边极值,第一次写就是极值弄错了。
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
int len = nums.size();
vector<int> Lnum(len), Rnum(len);
vector<int> result(len);
Lnum[0] = nums[0];
for(int i=1;i<len-1; i++){
Lnum[i] = Lnum[i-1]*nums[i];
}
Rnum[len-1] = nums[len-1];
for(int i=len-2; i>=0; i--)
Rnum[i] = Rnum[i+1]*nums[i];
for(int i=1;i<len-1;i++){
result[i] = Rnum[i+1] * Lnum[i-1];
}
result[0] = Rnum[1];
result[len-1] = Lnum[len-2];
return result;
}
};
41. 缺失的第一个正数
这题直接哈希了,map一下所有整数,先看有没有1,没有就直接返回1,其次遍历,找有没有比自己大1的键,就好了。
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
map<int,int> ma;
int result = 0;
for(const auto& n :nums){
if(n>0 && ma.find(n)==ma.end())
ma.insert(make_pair(n,1));
}
if(ma.find(1) == ma.end()){
result = 1;
return result;
}
for(const auto& m : ma){
if(ma.find((m.first)+1) == ma.end()){
result = (m.first)+1;
cout<<m.first<<endl;
break;
}
}
return result;
}
};
73. 矩阵置零
很容易想到,设置标志位表示原始值是不是0,然后两层for判断,是true就把行、列变为0。但实现起来怎么变为0呢,总不能再加一层for吧。纠结了半天;
其实,标志位不用设置二维,只需要确定某行、某列是否需要设置为0即可。
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
//vector<vector<bool>> flag(matrix.size(), vector<bool> (matrix[0].size(), false));
vector<bool> row(matrix.size()), col(matrix[0].size());
for(int i=0;i<matrix.size();i++)
for(int j=0;j<matrix[0].size();j++)
if(matrix[i][j] == 0)
row[i] = col[j] = true;
for(int i=0;i<matrix.size();i++)
for(int j=0;j<matrix[0].size();j++){
if(row[i] || col[j]){
matrix[i][j] = 0;
}
}
return;
}
};
54. 螺旋矩阵
这是真考验数组边界判定的题,思路很直观,就是按照要求顺时针遍历,涉及4个边界。
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
vector<int> result;
if(matrix.empty())
return result;
int u=0, d=matrix.size()-1, l=0, r=matrix[0].size()-1;
while(true){
for(int i=l;i<=r;i++)
result.push_back(matrix[u][i]);
if(++u>d)
break;
for(int i=u;i<=d;i++)
result.push_back(matrix[i][r]);
if(--r<l)
break;
for(int i=r;i>=l;i--)
result.push_back(matrix[d][i]);
if(--d<u)
break;
for(int i=d;i>=u;i--)
result.push_back(matrix[i][l]);
if(++l>r)
break;
}
return result;
}
};
53. 最大子数组和
两种思路,动态规划,dp[i]表示i之前的最大子数组之和,每次取+或者不+num[i]的中较大值就好。然后遍历dp,找最大值就行。代码可以优化,求dp时顺便把result也更新。
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int pre = 0;
int result = nums[0];
for(const auto& x : nums){
pre = max(pre+x, x);
result = max(result, pre);
}
return result;
}
};
方法二,正常数组做法,不过就是求和时判断是否为负,如果为负值,那一定会影响最大子数组的和,因此一定不是答案,就更新和为0,重新开始求和;这里也坑,第一次写,想简化逻辑,结果写扯了,写的结果是所有正数之和。。。还感觉自己逻辑没问题,排查了半天。
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int result = INT_MIN;
int add = 0;
for(int i=0; i<nums.size(); i++){
add += nums[i];
if(add>result)
result = add;
if(add<0)
add = 0;
}
return result;
}
};
56. 合并区间
这题很直观,就是根据每个区间的左边界进行排序,然后依次判断即可。
第一个区间的左边界是可以确定的,所以第一个区间放进去。从第二个区间开始判断(i),如果i得左边界小于result得右边界,说明有重叠,更新back得右边界为最大值即可。如果大于,那就没重叠,把i区间放入result即可
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
sort(intervals.begin(), intervals.end());
vector<vector<int>> result;
result.emplace_back(intervals[0]);
for(int i=1; i<intervals.size(); i++){
if(result.back()[1] >= intervals[i][0])
result.back()[1] = max(result.back()[1], intervals[i][1]);
else
result.emplace_back(intervals[i]);
}
return result;
}
};
48.旋转矩阵
有点抽象了,两种方法,第一种,找出反转后得行列变换规律,matrix[row][col],在旋转后,它的新位置为 new [col][n−row−1]。两层for遍历就好;第二种方法原地反转,不借用辅助空间,顺时针旋转90=水平翻转+主对角线反转。第一次写有些难想到
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int n = matrix.size();
auto matrix_new = matrix;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
matrix_new[j][n - i - 1] = matrix[i][j];
}
}
matrix = matrix_new;
}
};
240. 搜索二维矩阵Ⅱ
直接暴力就不说了,优化的话,每行有个二分搜索吧
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
for(const auto& row:matrix){
auto it = lower_bound(row.begin(), row.end(), target);
if(it != row.end() && *it==target)
return true;
}
return false;
}
};