算法训练营day2
1.有序数组的平方
给你一个按 非递减顺序 排序的整数数组 nums
,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
https://leetcode.cn/problems/squares-of-a-sorted-array/description/
class Solution { public: vector<int> sortedSquares(vector<int>& nums) { int pos_index = nums.size(); for (int i = 0; i < nums.size(); i++) { if (nums [i] >= 0) {pos_index = i;break;} } if (pos_index == 0) { for (auto & x: nums) x *= x; return nums; } else { vector<int> neg(nums.begin(), nums.begin() + pos_index); vector<int> pos(nums.begin() + pos_index, nums.end()); reverse(neg.begin(),neg.end()); for (auto &x:neg) x = (0-x); vector<int> ret; int neg_index = 0; int pos_index = 0; while (neg_index < neg.size() && pos_index < pos.size()) { if (neg[neg_index] < pos[pos_index]) { ret.push_back(neg[neg_index]); neg_index++; } else { ret.push_back(pos[pos_index]); pos_index++; } } if (neg_index < neg.size()) { for (;neg_index < neg.size();neg_index++) ret.push_back(neg[neg_index]); } if (pos_index < pos.size()) { for (;pos_index < pos.size();pos_index++) ret.push_back(pos[pos_index]); } for (auto &x: ret) x *= x; return ret; } } };
老师给出的使用双指针法:
vector<int> sortedSquares(vector<int>& A) { int k = A.size() - 1; vector<int> result(A.size(), 0); for (int i = 0, j = A.size() - 1; i <= j;) { // 注意这里要i <= j,因为最后要处理两个元素 if (A[i] * A[i] < A[j] * A[j]) { result[k--] = A[j] * A[j]; j--; } else { result[k--] = A[i] * A[i]; i++; } } return result; }
2.长度最小的子数组
给定一个含有 n
个正整数的数组和一个正整数 target
。
找出该数组中满足其总和大于等于 target
的长度最小的 连续
[numsl, numsl+1, ..., numsr-1, numsr]
,并返回其长度。如果不存在符合条件的子数组,返回 0
。
https://leetcode.cn/problems/minimum-size-subarray-sum/description/
class Solution { public: int sub_sum(vector<int>& nums, int first_index ,int first_len) { if (first_len <= 0) return 0; int sum = 0; for (int i = first_index - first_len + 1; i <= first_index; i++) sum += nums[ i ]; return sum; } int shrink_len(int target, vector<int>& nums, int first_index ,int first_len) { //printf("first_index:%d first_len:%d\n", first_index,first_len); int sum = 0; int count = 0; for(int i = first_index; i > first_index - first_len; i--) { count++; sum += nums[i]; if (sum >= target) {return count;} } return first_len; } int minSubArrayLen(int target, vector<int>& nums) { int first_len = 0; int sum = 0; int first_index = 0; for (int i = 0; i < nums.size(); i++) { sum += nums[ i ]; if (sum >= target) { first_index = i; first_len = i + 1; int shrinklen = shrink_len(target, nums, first_index ,first_len); if (shrinklen < first_len) first_len = shrinklen; break; } } //printf("111111 %d\n", first_len); for (int i = first_index + 1; i < nums.size(); i++) { int sum = sub_sum(nums, i, first_len - 1); if (sum >= target) { first_len = first_len - 1; int shrinklen = shrink_len(target, nums, i ,first_len); if (shrinklen < first_len) first_len = shrinklen; } } return first_len; } };
有待优化地方:
1.
int sum = sub_sum(nums, i, first_len - 1);
每次都是重复计算
2.
shrink_len 从后往前,不利于命中缓存,遍历性能较差
老师给出的更精简&快速的方法:
int minSubArrayLen(int s, vector<int>& nums) { int result = INT32_MAX; int sum = 0; // 滑动窗口数值之和 int i = 0; // 滑动窗口起始位置 int subLength = 0; // 滑动窗口的长度 for (int j = 0; j < nums.size(); j++) { sum += nums[j]; // 注意这里使用while,每次更新 i(起始位置),并不断比较子序列是否符合条件 while (sum >= s) { subLength = (j - i + 1); // 取子序列的长度 result = result < subLength ? result : subLength; sum -= nums[i++]; // 这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置) } } // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列 return result == INT32_MAX ? 0 : result; }