【数组】
1 53. 最大子数组和
方法1:前缀和 + 一点技巧(好像是贪心):一个记录当前遍历位置前的最小前缀和。再利用一个int记录差值最大的值
我一开始只想到前缀和,但是O(n^2)超时,后来找到个题解加上一点技巧就可以在前缀和的 基础上降到O(n)。
class Solution
{
public:
int maxSubArray(vector<int> &nums)
{
int sum[100010];
memset(sum,sizeof(sum),0);
for(int i = 1; i <= nums.size();i++) // 1...n
sum[i] = sum[i-1] + nums[i-1];
int low = INT_MAX;
int dif = INT_MIN;
for(int i = 0; i <= nums.size();i++) /// sum[j] - sum[i] 并且(j>i)求个max
{
// 一个记录当前遍历位置前的最小前缀和
// 再利用一个int记录差值最大的值
dif = max(dif , sum[i] - low); // 目前最大的差值
low = min(low , sum[i]); //必须要先更新max,再更新min,防止min和i重合
}
if(nums.size() == 1)return nums[0];
return dif;
}
};
方法2:动态规划法:
dp做起来比上面那个方法轻松一百倍,我服了,上面那个有点技巧还易错,dp就是个极简单的问题。ac:
class Solution {
public:
// dp做一次
int dp[100010]; // 以i结尾的连续子数组最大的和
/*
if(dp[j-1] > 0)
dp[j] = dp[j-1] + nums[j];
else dp[j] = nums[j];
dp[0] = nums[0]
j++;
*/
int maxSubArray(vector<int>& nums) {
dp[0] = nums[0];
int ans = dp[0];
for(int j = 1; j < nums.size();j++)
{
if(dp[j-1] > 0)
dp[j] = dp[j-1] + nums[j];
else dp[j] = nums[j];
ans = max(ans,dp[j]);
}
return ans;
}
};
2 56. 合并区间
典型贪心,AC代码:
class Solution {
public:
static bool cmp(vector<int> a, vector<int> b)
{
return a[0] < b[0];
}
vector<vector<int>> merge(vector<vector<int>>& intervals) {
// 贪心
sort(intervals.begin(),intervals.end(),cmp);
vector<vector<int>> ans;
vector<int> tmp;
int l = intervals[0][0];
int r = intervals[0][1];
for(int i = 1; i < intervals.size();i++)
{
if(intervals[i][0] > r)
{
tmp.clear();
tmp.push_back(l);
tmp.push_back(r);
ans.push_back(tmp);
l = intervals[i][0];
r = intervals[i][1];
}
else if(intervals[i][1] > r) r = intervals[i][1];
}
tmp.clear();
tmp.push_back(l);
tmp.push_back(r);
ans.push_back(tmp);
return ans;
}
};
3 189. 轮转数组(多种解法,todo)
一种写法的AC代码:
class Solution {
public:
void rotate(vector<int>& nums, int k) {
//法1:再开一个vector 存完之后替换nums
//法2:把前面的push_back到后面 然后全部前移动,resize
//法3:
int size = nums.size();
k %= size; // 注意k的取值范围不是 小于size
for(int i = 0; i < size - k;i++)
nums.push_back(nums[i]);
for(int i = 0,j = size - k; i < size;i++,j++)
nums[i] = nums[j];
nums.resize(size);
return;
}
};
4 238. 除自身以外数组的乘积
用了pat学到的:左右两次遍历大法
AC代码:
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums)
{
vector<int> ans(nums.size());
ans[0] = 0;
ans[1] = nums[0];
for(int i = 2; i < nums.size();i++)
ans[i] = nums[i-1]*ans[i-1];
int tmp = 1;
for(int i = nums.size()-1; i >= 0; i--)
{
if(i == nums.size()-1)
{
}
else if(i == 0)
{
ans[i] = tmp;
}
else
{
ans[i] = tmp*ans[i];
}
tmp *= nums[i];
cout << i << " " << tmp << endl;
}
return ans;
}
};
// 2 3 4
5
【矩阵】
1 73. 矩阵置零
我的方法和题解方法见注释,AC代码:
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
// 我的方法:
// 时间复杂度O(m*n) 空间复杂度O(m+n)
// 遍历一遍 找到0位置的行列存起来
// 再遍历一次 画0
// 题解:
/*
思路二: 用O(1)O(1)O(1)空间
关键思想: 用matrix第一行和第一列记录该行该列是否有0,作为标志位
但是对于第一行,和第一列要设置一个标志位,为了防止自己这一行(一列)也有0的情况.注释写在代码里,直接看代码很好理解!
*/
unordered_set<int> line;
unordered_set<int> vol;
for(int i = 0; i < matrix.size();i++)
{
for(int j = 0; j < matrix[i].size();j++)
{
if(matrix[i][j] == 0)
{
line.insert(i);
vol.insert(j);
}
}
}
for(auto i : line)
{
for(int j = 0; j < matrix[i].size();j++)
matrix[i][j] = 0;
}
for(auto i : vol)
{
for(int j = 0; j < matrix.size();j++)
matrix[j][i] = 0;
}
}
};