LeetCode 热题 100:普通数组
53. 最大子数组和
给你一个整数数组
nums
,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。子数组是数组中的一个连续部分。
示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4] 输出:6 解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
示例 2:
输入:nums = [1] 输出:1
示例 3:
输入:nums = [5,4,-1,7,8] 输出:23
提示:
1 <= nums.length <= 10^5
-10^4 <= nums[i] <= 10^4
**进阶:**如果你已经实现复杂度为
O(n)
的解法,尝试使用更为精妙的 分治法 求解。
int maxSubArray(vector<int>& nums) {int n = nums.size();// i结尾最大子数组和vector<int> dp(n);dp[0] = nums[0];int ans = dp[0];for (int i = 1; i < n; ++i) {dp[i] = max(dp[i - 1] + nums[i], nums[i]);ans = max(ans, dp[i]);}return ans;
}
56. 合并区间
以数组
intervals
表示若干个区间的集合,其中单个区间为intervals[i] = [starti, endi]
。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。示例 1:
输入:intervals = [[1,3],[2,6],[8,10],[15,18]] 输出:[[1,6],[8,10],[15,18]] 解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
示例 2:
输入:intervals = [[1,4],[4,5]] 输出:[[1,5]] 解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。
提示:
1 <= intervals.length <= 10^4
intervals[i].length == 2
0 <= starti <= endi <= 10^4
vector<vector<int>> merge(vector<vector<int>>& intervals) {sort(intervals.begin(), intervals.end());vector<vector<int>> ans;for (int i = 0; i < intervals.size(); ++i) {int left = intervals[i][0], right = intervals[i][1];if (ans.empty() || ans.back()[1] < left) {ans.push_back({left, right});} else {ans.back()[1] = max(ans.back()[1], right);}}return ans;
}
189. 轮转数组
给定一个整数数组
nums
,将数组中的元素向右轮转k
个位置,其中k
是非负数。示例 1:
输入: nums = [1,2,3,4,5,6,7], k = 3 输出: [5,6,7,1,2,3,4] 解释: 向右轮转 1 步: [7,1,2,3,4,5,6] 向右轮转 2 步: [6,7,1,2,3,4,5] 向右轮转 3 步: [5,6,7,1,2,3,4]
示例 2:
输入:nums = [-1,-100,3,99], k = 2 输出:[3,99,-1,-100] 解释: 向右轮转 1 步: [99,-1,-100,3] 向右轮转 2 步: [3,99,-1,-100]
提示:
1 <= nums.length <= 10^5
-2^31 <= nums[i] <= 2^31 - 1
0 <= k <= 10^5
void rotate(vector<int>& nums, int k) {int n = nums.size();k %= n;reverse(nums, 0, n-1);reverse(nums, 0, k-1);reverse(nums, k, n-1);
}void reverse(vector<int>& nums, int left, int right) {while (left < right) {swap(nums[left++], nums[right--]);}
}
238. 除自身以外数组的乘积
给你一个整数数组
nums
,返回 数组answer
,其中answer[i]
等于nums
中除nums[i]
之外其余各元素的乘积 。题目数据 保证 数组
nums
之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。请 **不要使用除法,**且在
O(n)
时间复杂度内完成此题。示例 1:
输入: nums = [1,2,3,4] 输出: [24,12,8,6]
示例 2:
输入: nums = [-1,1,0,-3,3] 输出: [0,0,9,0,0]
提示:
2 <= nums.length <= 10^5
-30 <= nums[i] <= 30
- 保证 数组
nums
之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内**进阶:**你可以在
O(1)
的额外空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组 不被视为 额外空间。)
与这题724. 寻找数组的中心下标类似。分别构建从前往后的乘积数组dp1
,以及从后往前的乘积数组dp2
,再初始化ans
数组即可。
vector<int> productExceptSelf(vector<int>& nums) {int n = nums.size();vector<int> dp1(n + 1);dp1[0] = 1;for (int i = 1; i <= n; ++i)dp1[i] = dp1[i - 1] * nums[i - 1];vector<int> dp2(n + 2);dp2[n + 1] = 1;for (int j = n; j > 0; --j)dp2[j] = dp2[j + 1] * nums[j - 1];vector<int> ans(n);for (int i = 0; i < n; ++i)ans[i] = dp1[i] * dp2[i + 2];return ans;
}
在此基础上还可以优化空间复杂度,先用ans
作为从前往后的乘积数组dp1
,sum作为从后往前的乘积和,再从后往前更新ans。
vector<int> productExceptSelf(vector<int>& nums) {int n = nums.size();vector<int> ans(n);ans[0] = 1;for (int i = 1; i < n; ++i)ans[i] = ans[i - 1] * nums[i - 1];int sum = 1;for (int i = n - 1; i >= 0; --i) {ans[i] *= sum;sum *= nums[i];}return ans;
}
41. 缺失的第一个正数
给你一个未排序的整数数组
nums
,请你找出其中没有出现的最小的正整数。请你实现时间复杂度为
O(n)
并且只使用常数级别额外空间的解决方案。示例 1:
输入:nums = [1,2,0] 输出:3 解释:范围 [1,2] 中的数字都在数组中。
示例 2:
输入:nums = [3,4,-1,1] 输出:2 解释:1 在数组中,但 2 没有。
示例 3:
输入:nums = [7,8,9,11,12] 输出:1 解释:最小的正数 1 没有出现。
提示:
1 <= nums.length <= 105
-231 <= nums[i] <= 231 - 1
哈希表,时间复杂度O(n),空间复杂度O(n)
int firstMissingPositive(vector<int>& nums) {unordered_set<int> hash;for (int num : nums) {hash.insert(num);}int ans = 1;while (1) {if (!hash.count(ans)) {return ans;}ans++;}return -1;
}
置换,时间复杂度O(n),空间复杂度O(1)
int firstMissingPositive(vector<int>& nums) {int n = nums.size();for (int i = 0; i < n; ++i) {while (nums[i] > 0 && nums[i] <= n && nums[nums[i]-1] != nums[i]) {swap(nums[nums[i] - 1], nums[i]);}}for (int i = 0; i < n; ++i) {if (nums[i] != i + 1) {return i + 1;}}return n + 1;
}