大连公路建设有限公司网站,公司的建设网站公司,网站建设lnmp,南阳建网站1、最大子数组和给你一个整数数组 nums #xff0c;请你找出一个具有最大和的连续子数组#xff08;子数组最少包含一个元素#xff09;#xff0c;返回其最大和。子数组是数组中的一个连续部分。示例 1#xff1a;输入#xff1a;nums [-2,1,-3,4,-1,2,1,-5,4]
输出请你找出一个具有最大和的连续子数组子数组最少包含一个元素返回其最大和。子数组是数组中的一个连续部分。示例 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 1e5-1e4 nums[i] 1e4class Solution { public: int maxSubArray(vectorint nums) { int pre 0, maxAns nums[0]; for (const auto x: nums) { pre max(pre x, x); maxAns max(maxAns, pre); } return maxAns; } };2、合并区间以数组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] 可被视为重叠区间。示例 3输入intervals [[4,7],[1,4]]输出[[1,7]]解释区间 [1,4] 和 [4,7] 可被视为重叠区间。提示1 intervals.length 1e4intervals[i].length 20 starti endi 1e4方法一排序思路如果我们按照区间的左端点排序那么在排完序的列表中可以合并的区间一定是连续的。如下图所示标记为蓝色、黄色和绿色的区间分别可以合并成一个大区间它们在排完序的列表中是连续的算法我们用数组 merged 存储最终的答案。首先我们将列表中的区间按照左端点升序排序。然后我们将第一个区间加入 merged 数组中并按顺序依次考虑之后的每个区间如果当前区间的左端点在数组 merged 中最后一个区间的右端点之后那么它们不会重合我们可以直接将这个区间加入数组 merged 的末尾否则它们重合我们需要用当前区间的右端点更新数组 merged 中最后一个区间的右端点将其置为二者的较大值。class Solution { public: vectorvectorint merge(vectorvectorint intervals) { if (intervals.size() 0) { return {}; } sort(intervals.begin(), intervals.end()); vectorvectorint merged; for (int i 0; i intervals.size(); i) { int L intervals[i][0], R intervals[i][1]; if (!merged.size() || merged.back()[1] L) { merged.push_back({L, R}); } else { merged.back()[1] max(merged.back()[1], R); } } return merged; } };3、轮转数组给定一个整数数组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 1e5-231 nums[i] 231 - 10 k 1e5方法一使用额外的数组我们可以使用额外的数组来将每个元素放至正确的位置。用 n 表示数组的长度我们遍历原数组将原数组下标为 i 的元素放至新数组下标为 (ik)modn 的位置最后将新数组拷贝至原数组即可。class Solution { public: void rotate(vectorint nums, int k) { int n nums.size(); vectorint newArr(n); for (int i 0; i n; i) { newArr[(i k) % n] nums[i]; } nums.assign(newArr.begin(), newArr.end()); } };方法三数组翻转该方法基于如下的事实当我们将数组的元素向右移动 k 次后尾部 kmodn 个元素会移动至数组头部其余元素向后移动 kmodn 个位置。该方法为数组的翻转我们可以先将所有元素翻转这样尾部的 kmodn 个元素就被移至数组头部然后我们再翻转 [0,kmodn−1] 区间的元素和 [kmodn,n−1] 区间的元素即能得到最后的答案。我们以 n7k3 为例进行如下展示操作 结果原始数组 1 2 3 4 5 6 7翻转所有元素 7 6 5 4 3 2 1翻转 [0,kmodn−1] 区间的元素 5 6 7 4 3 2 1翻转 [kmodn,n−1] 区间的元素 5 6 7 1 2 3 4class Solution { public: void reverse(vectorint nums, int start, int end) { while (start end) { swap(nums[start], nums[end]); start 1; end - 1; } } void rotate(vectorint nums, int k) { k % nums.size(); reverse(nums, 0, nums.size() - 1); reverse(nums, 0, k - 1); reverse(nums, k, nums.size() - 1); } };4、除自身以外数组的乘积给你一个整数数组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 105-30 nums[i] 30输入保证数组answer[i]在32 位整数范围内进阶你可以在O(1)的额外空间复杂度内完成这个题目吗 出于对空间复杂度分析的目的输出数组不被视为额外空间。方法一左右乘积列表思路我们不必将所有数字的乘积除以给定索引处的数字得到相应的答案而是利用索引左侧所有数字的乘积和右侧所有数字的乘积即前缀与后缀相乘得到答案。对于给定索引 i我们将使用它左边所有数字的乘积乘以右边所有数字的乘积。下面让我们更加具体的描述这个算法。算法初始化两个空数组 L 和 R。对于给定索引 iL[i] 代表的是 i 左侧所有数字的乘积R[i] 代表的是 i 右侧所有数字的乘积。我们需要用两个循环来填充 L 和 R 数组的值。对于数组 LL[0] 应该是 1因为第一个元素的左边没有元素。对于其他元素L[i] L[i-1] * nums[i-1]。同理对于数组 RR[length-1] 应为 1。length 指的是输入数组的大小。其他元素R[i] R[i1] * nums[i1]。当 R 和 L 数组填充完成我们只需要在输入数组上迭代且索引 i 处的值为L[i] * R[i]。class Solution { public: vectorint productExceptSelf(vectorint nums) { int length nums.size(); // L 和 R 分别表示左右两侧的乘积列表 vectorint L(length, 0), R(length, 0); vectorint answer(length); // L[i] 为索引 i 左侧所有元素的乘积 // 对于索引为 0 的元素因为左侧没有元素所以 L[0] 1 L[0] 1; for (int i 1; i length; i) { L[i] nums[i - 1] * L[i - 1]; } // R[i] 为索引 i 右侧所有元素的乘积 // 对于索引为 length-1 的元素因为右侧没有元素所以 R[length-1] 1 R[length - 1] 1; for (int i length - 2; i 0; i--) { R[i] nums[i 1] * R[i 1]; } // 对于索引 i除 nums[i] 之外其余各元素的乘积就是左侧所有元素的乘积乘以右侧所有元素的乘积 for (int i 0; i length; i) { answer[i] L[i] * R[i]; } return answer; } };5、缺失的第一个正数给你一个未排序的整数数组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 1e5-2^31 nums[i] 2^31 - 1前言如果本题没有额外的时空复杂度要求那么就很容易实现我们可以将数组所有的数放入哈希表随后从 1 开始依次枚举正整数并判断其是否在哈希表中我们可以从 1 开始依次枚举正整数并遍历数组判断其是否在数组中。如果数组的长度为 N那么第一种做法的时间复杂度为 O(N)空间复杂度为 O(N)第二种做法的时间复杂度为 O(N^2)空间复杂度为 O(1)。但它们都不满足时间复杂度为 O(N) 且空间复杂度为 O(1)。「真正」满足时间复杂度为 O(N) 且空间复杂度为 O(1) 的算法是不存在的但是我们可以退而求其次利用给定数组中的空间来存储一些状态。也就是说如果题目给定的数组是不可修改的那么就不存在满足时空复杂度要求的算法但如果我们可以修改给定的数组那么是存在满足要求的算法的。方法一哈希表对于「前言」中提到的第一种做法我们可以将数组所有的数放入哈希表随后从 1 开始依次枚举正整数并判断其是否在哈希表中。仔细想一想我们为什么要使用哈希表这是因为哈希表是一个可以支持快速查找的数据结构给定一个元素我们可以在 O(1) 的时间查找该元素是否在哈希表中。因此我们可以考虑将给定的数组设计成哈希表的「替代产品」。实际上对于一个长度为 N 的数组其中没有出现的最小正整数只能在 [1,N1] 中。这是因为如果 [1,N] 都出现了那么答案是 N1否则答案是 [1,N] 中没有出现的最小正整数。这样一来我们将所有在 [1,N] 范围内的数放入哈希表也可以得到最终的答案。而给定的数组恰好长度为 N这让我们有了一种将数组设计成哈希表的思路我们对数组进行遍历对于遍历到的数 x如果它在 [1,N] 的范围内那么就将数组中的第 x−1 个位置注意数组下标从 0 开始打上「标记」。在遍历结束之后如果所有的位置都被打上了标记那么答案是 N1否则答案是最小的没有打上标记的位置加 1。那么如何设计这个「标记」呢由于数组中的数没有任何限制因此这并不是一件容易的事情。但我们可以继续利用上面的提到的性质由于我们只在意 [1,N] 中的数因此我们可以先对数组进行遍历把不在 [1,N] 范围内的数修改成任意一个大于 N 的数例如 N1。这样一来数组中的所有数就都是正数了因此我们就可以将「标记」表示为「负号」。算法的流程如下我们将数组中所有小于等于 0 的数修改为 N1我们遍历数组中的每一个数 x它可能已经被打了标记因此原本对应的数为 ∣x∣其中 ∣∣ 为绝对值符号。如果 ∣x∣∈[1,N]那么我们给数组中的第 ∣x∣−1 个位置的数添加一个负号。注意如果它已经有负号不需要重复添加在遍历完成之后如果数组中的每一个数都是负数那么答案是 N1否则答案是第一个正数的位置加 1。class Solution { public: int firstMissingPositive(vectorint nums) { int n nums.size(); for (int num: nums) { if (num 0) { num n 1; } } for (int i 0; i n; i) { int num abs(nums[i]); if (num n) { nums[num - 1] -abs(nums[num - 1]); } } for (int i 0; i n; i) { if (nums[i] 0) { return i 1; } } return n 1; } };