一. 977.有序数组的平方
给你一个按 非递减顺序 排序的整数数组
nums
,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。示例 1:
输入:nums = [-4,-1,0,3,10] 输出:[0,1,9,16,100] 解释:平方后,数组变为 [16,1,0,9,100] 排序后,数组变为 [0,1,9,16,100]
示例 2:
输入:nums = [-7,-3,2,3,11] 输出:[4,9,9,49,121]提示:
1 <= nums.length <= 104
-104 <= nums[i] <= 104
nums
已按 非递减顺序 排序进阶:
- 请你设计时间复杂度为
O(n)
的算法解决本问题
这道题目的标签可以划归为: 双指针, 合并有序数组
非递减的同义词就是递增或者相等,也就是说原数组中靠右的数字总是比靠左边的数字大或者相同,这是本道题目的基础数学关系。
在此基础上,对数组的每一个元素进行操作,计算平方值,由于负数进行平方之后就会增大,此刻原本的大小关系就不再适用,所以我们可以将原本的数组划分为两个部分: 负数部分,正数部分。
正数部分按照原本的顺序计算平方之后直接返回,负数部分则需要替换原本的顺序。
划分为两个部分:也就是标准的双指针的标志
同时也由于这样的考量将这个问题划分为了三种情况来解决:
1. 数组全部都大于等于0
2. 数组都全部小于等于0
3. 数组至少存在这样一个结构 [...., 负数,0, 正数,...]
双指针是在第三种情况下用于遍历数组使用,因为在第三种情况下同时存在着两个数组,且自问题就变成了合并两个递增数组,这样就需要直接套用先前的方案加入来解决这个问题。
依照这个思路,设计代码如下:
func sortedSquares(nums []int) []int {
left,right, l := 0, len(nums)-1,len(nums)
result := make([]int, l)
if nums[0] >= 0 {
for i := 0; i < l ; i++{
nums[i] = double(nums[i])
}
return nums
}
if nums[right] <= 0 {
for i := right; i >= 0 ; i--{
result[right-i] = double(nums[i])
}
return result
}
count := 0
for left <= right {
count++
a, b := abs(nums[left]), abs(nums[right])
if a > b {
result[l-count] = double(a)
left++
}else{
result[l-count] = double(b)
right--
}
}
return result
}
func double(a int) int {
return a*a
}
func abs(a int) int {
if a < 0 {
return -a
}
return a
}
二. 209 长度最小的字数组
给定一个含有
n
个正整数的数组和一个正整数target
。找出该数组中满足其和
≥ target
的长度最小的 连续子数组[numsl, numsl+1, ..., numsr-1, numsr]
,并返回其长度。如果不存在符合条件的子数组,返回0
输入:target = 7, nums = [2,3,1,2,4,3] 输出:2 解释:子数组 [4,3] 是该条件下的长度最小的子数组。 示例 2: 输入:target = 4, nums = [1,4,4] 输出:1 示例 3: 输入:target = 11, nums = [1,1,1,1,1,1,1,1] 输出:0 提示: 1 <= target <= 109 1 <= nums.length <= 105 1 <= nums[i] <= 105进阶:
- 如果你已经实现
O(n)
时间复杂度的解法, 请尝试设计一个O(n log(n))
时间复杂度的解法。
这个问题可以分解为两个先后关系的子问题:
1. 得到一个连续子数组并计算和与 target 的关系
2. 如何获得下一个子数组
第一个问题是简单的,就是计算累加和并比较大小
第二个问题则不只是具有自己的逻辑,还会在第一个问题结论的基础上做变换
首先是得到下一个数组的方式==》 通过双指针的方式,当sum 小于 target 的时候,移动右指针增加一个数,当 sum 大于等于 target满足条件之后,需要寻找下一个数组,就需要移动左指针使得双指针之间的数组和不满足条件
这其中的关键点事:
1. 每次移动之后需要在 sum 中减去最左边的数
2. 考虑循环结束之后,右指针到达边界但是左指针还在继续移动的情况,所以需要给左指针一个结束的条件
最终按照上述的思路实现的代码如下:
func minSubArrayLen(target int, nums []int) int {
ans , sum , l := len(nums)+1, 0, len(nums)
left, right := 0, 0
if l <= 0 {
return 0
}
for right < l {
sum += nums[right]
for sum >= target {
ans = min(ans,right-left+1)
// 每次都剪去左边踢出的数字
sum -= nums[left]
left++
}
right++
}
if ans > l {
return 0
}
return ans
}
func min(a int , b int) int{
if a < b {
return a
}
return b
}