题目描述
解法一:滑窗(Python)
利用滑窗,记录窗口中的最小值和最大值,当新加入元素与最大值或最小值的绝对差大于限制值之后(我们需要记录是哪种情况的触发,是最大值的绝对差不符合,还是最小值的绝对差不符合,再或者两种情况都不符合),按照触发的情况找到窗口中不符合条件的元素下标(两种情况都不符合时,我们寻找最大下标),然后将窗口在此下标之前的元素全部弹出(包括下标所指的当前元素)。重复此过程,当窗口中的元素都符合条件时,再操作下一个新加入元素。
注意两种特殊情况的判定:
- n u m s [ . . . ] nums[...] nums[...]只有一个元素时,直接返回1
- n u m s [ . . . ] nums[...] nums[...]全是一个元素时,直接返回 l e n ( n u m s ) len(nums) len(nums)
class Solution:
def longestSubarray(self, nums: List[int], limit: int) -> int:
wmd, mmin, mmax, mmin_indx, mmax_indx, res = [nums[0]], nums[0], nums[0], 0, 0, 1
if len(nums) == 1: return res
for i in range(1, len(nums)):
if nums[i] == nums[i-1]: res += 1
else: break
if res == len(nums): return res
for i in range(1, len(nums)):
wmd.append(nums[i])
while abs(nums[i] - mmin) > limit or abs(nums[i] - mmax) > limit:
if abs(nums[i] - mmin) > limit and abs(nums[i] - mmax) > limit:
mmin_indx = wmd.index(mmin)
mmax_indx = wmd.index(mmax)
indx = max(mmin_indx, mmax_indx)
wmd = wmd[indx + 1:]
mmin, mmax = min(wmd), max(wmd)
elif abs(nums[i] - mmin) > limit:
mmin_indx = wmd.index(mmin)
wmd = wmd[mmin_indx + 1:]
mmin, mmax = min(wmd), max(wmd)
elif abs(nums[i] - mmax) > limit:
mmax_indx = wmd.index(mmax)
indx = min(mmax_indx, mmax_indx)
wmd = wmd[indx + 1:]
mmin, mmax = min(wmd), max(wmd)
mmin, mmax = min(wmd), max(wmd)
res = max(res, len(wmd))
return res
换种写法
虽然我自己觉得我的代码没啥神操作的,但是lc平台上跑出来就莫名其妙双百了,我也很迷 Σ( ° △ °|||)︴
下面我们看看其他大佬的简便写法,但是思想都是一样的:利用滑窗,同时记录一些关键信息。
对于关键信息也就是最大值和最小值,那么思路有两:
- 用容器自身的有序性
- 用优先队列,也就是堆
第一个(C++):运用了 map 的有序性,来记录最大值和最小值
class Solution {
public:
int longestSubarray(vector<int>& nums, int limit) {
map<int, int> m;
int ans = 0;
int i = 0;
for(int j=0;j<nums.size();j++)
{
m[nums[j]]++;
// map是有序的,用最大值减去最小值
while(m.rbegin()->first-m.begin()->first>limit)
{
m[nums[i]]--;
if(m[nums[i]]==0) m.erase(nums[i]);
i++;
}
ans = max(ans, j-i+1);
}
return ans;
}
};
第二个(C++):运用 multiset
class Solution {
public:
int longestSubarray(vector<int>& nums, int limit) {
multiset<int> s;
int ans = 0, i = 0;
for(int j=0;j<nums.size();j++)
{
s.insert(nums[j]);
while(*s.rbegin()-*s.begin()>limit)
{
s.erase(s.find(nums[i]));
i++;
}
ans = max(ans, j-i+1);
}
return ans;
}
};
第三个(Python):运用 heapq 建大顶堆和小顶堆
class Solution:
def longestSubarray(self, nums: List[int], limit: int) -> int:
mmax, mmin, left, res = [], [], 1, 0
for right, num in enumerate(nums, 1):
heapq.heappush(mmax, (-num, right)) # 大顶堆,但是heapq默认的是小顶堆,所以在num前取了负值
heapq.heappush(mmin, (num, right))
while -mmin[0][0] - mmax[0][0] >limit:
# 删除left左边的元素
while mmin[0][1] <= left: heapq.heappop(mmin)
while mmax[0][1] <= left: heapq.heappop(mmax)
left += 1
res = max(res, right - left + 1)
return res