今日题目
题目 | 难度 | 备注 |
---|---|---|
1. 两数之和 | 暴力求解,需优化 | |
704. 二分查找 - 力扣(LeetCode) | 简单 | 不是很熟练 |
27. 移除元素 - 力扣(LeetCode) | 简单 | |
977. 有序数组的平方 - 力扣(LeetCode) | 简单 | 得加强双指针思想 |
209. 长度最小的子数组 - 力扣(LeetCode) | 中等 | ♥ |
59. 螺旋矩阵 II - 力扣(LeetCode) | 中等 | ♥♥♥ |
数组篇
题目:1.两数之和
一、 源代码
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> ans;
for(int i=0;i<nums.size()-1;i++){
for(int j=i+1;j<nums.size();j++){
if(nums[i]+nums[j]==target){
ans.push_back(i);
ans.push_back(j);
return ans;
}
}
}
return {};
}
};
二、优化思路
考虑过把nums[i] 的值和 下标i 绑定在一起,但是却只想到用数组绑定,瞬间没有思路了。这是对数据结构的不熟悉,殊不知map 就是用来绑定两个数值的(当然其他数据类型也可以绑定)
把nums[i] 当key,i 当value,绑定后就好做了。令 x =nums[i],则只要在map中查找 target - x 就行,若查找成功则输出 “x = nums[i] ” 中的 i 和 map中的value就行;没查到说明没有满足的,直接把num[i] 和 i 压入map继续查找就行
三、优化代码
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> hamap;
int x = -1;
for (int i = 0; i < nums.size(); i++)
{
x = target - nums[i];
if (hamap.find(x) != hamap.end())
{
return{ hamap.find(x)->second, i };
}
hamap[nums[i]] = i;
}
return {}; /*注意方法 一定要return;
}
};
题目:977. 有序数组的平方
一、 源代码
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
vector<int> ans;
for(int i = 0; i < nums.size() ; i++){
int n = abs(nums[i]);
ans.push_back(n*n);
}
sort(ans.begin(),ans.end());
return ans;
}
};
二、优化思路
数组a不降序且值从负到正,再平方插入数组b,要求b不降序;
若把数组a从下标0 到 a.size()-1 的值平方,所得的数组应该是先降序再升序;
处理两头大中间小,成不降序;用什么方法呢?当然是双指针,选择较大的数逆序放入b就行;
三、优化代码
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int n = nums.size();
vector<int> ans(n);
for (int i = 0, j = n - 1, pos = n - 1; i <= j;) {
if (nums[i] * nums[i] > nums[j] * nums[j]) {
ans[pos] = nums[i] * nums[i];
++i;
}
else {
ans[pos] = nums[j] * nums[j];
--j;
}
--pos;
}
return ans;
}
};
X 题目:209. 长度最小的子数组
一、 源代码
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int a[200][200]; //a[i][j]表示i与j 之间连续子数组和
a[0][0] = nums[0];
int ans = 1e9,flag;
for(int j=1;j<nums.size();j++){
a[0][j] = a[0][j-1] + nums[j];
}
for(int i = 0,flag = 0; i < nums.size(); i++){
for(int j = nums.size() - 1; j >= 0; j--){
if(a[i][j] < target){
flag = 1;
break;
}
if(a[i][j] == target && ans > j-i+1){
ans = j-i+1;
}
if(a[i][j] > target ){
a[i+1][j] = a[i][j] - nums[i];
a[i][j-1] = a[i][j] - nums[j];
}
}
}
return (ans==1e9)? 0:ans;
}
};
二、错误原因
看错题目了,以为是找出该数组中满足其总和等于 target
的长度最小的 连续子数组 。原来是大于等于即可。那用一个for循环就行
三、改正代码
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
int n = nums.size();
if (n == 0) {
return 0;
}
int ans = INT_MAX;
vector<int> sums(n + 1, 0);
// 为了方便计算,令 size = n + 1
// sums[0] = 0 意味着前 0 个元素的前缀和为 0
// sums[1] = A[0] 前 1 个元素的前缀和为 A[0]
// 以此类推
for (int i = 1; i <= n; i++) {
sums[i] = sums[i - 1] + nums[i - 1];
}
for (int i = 1; i <= n; i++) {
int target = s + sums[i - 1];
auto bound = lower_bound(sums.begin(), sums.end(), target);
if (bound != sums.end()) {
ans = min(ans, static_cast<int>((bound - sums.begin()) - (i - 1)));
}
}
return ans == INT_MAX ? 0 : ans;
}
};
四、优化思路
源代码中其实存在很多问题:
1、为表示下标 i 到 j 中连续子数组值的和,居然选择用二维数组,这大大浪费了存储空间,而且二维数组并不能存多大,哪怕用个结构体都比这个好。
所以像本体求的连续子数组的和大于等于 target,是不是可以不用数组呢?靠双指针不停移动来更新ans
2、为了使用双指针不停移动来更新ans,选择了从两端往中间移动,先让 j = nums.size() - 1,若a[i] [j] > target 再分别讨论 a[i+1] [j] 和 a[i] [j-1] 这两种情况,这样则要么使用DFS,要么用二维数组或结构体(发现没有,其实可以不用数组)
所以若双指针 i,j 都从起点开始移动,会怎么样呢?定义sum为连续子数组值的和,sum < target 当然是 ++j,sum > target 那 j 不动,sum - nums[i] 后 i++,是不是比 i,j 从两端开始往中间移动好一点
五、优化代码
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
int n = nums.size();
if (n == 0) {
return 0;
}
int ans = INT_MAX;
int start = 0, end = 0;
int sum = 0;
while (end < n) {
sum += nums[end];
while (sum >= s) {
ans = min(ans, end - start + 1);
sum -= nums[start];
start++;
}
end++;
}
return ans == INT_MAX ? 0 : ans;
}
};
♥ X 题目:59. 螺旋矩阵 II
毫无思路