剑指offer--数组中的逆序对and滑动窗口的最大值

题目1:

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

示例 1:

输入: [7,5,6,4]
输出: 5

思路:归并排序算法。可以在归并排序最后将小数组变为大数组的时候,用两个指针分别指向左边数组和右边数组,判断i和j的关系,如果nums[i]>nums[j],那从i到mid的元素都可以和j形成逆序对,加上相对应的mid-i+1就可以了。主要代码还是归并排序算法,只不过在归并排序的合并的时候,加上一行代码进行了判断。

代码:

class Solution:
    def reversePairs(self, nums: List[int]) -> int:
        self.count=0
        def mergesort(nums,left,right):
            if left>=right:return
            mid=(left+right)//2
            mergesort(nums,left,mid)#划分左边
            mergesort(nums,mid+1,right)#划右边
            merge(nums,left,mid,right)#合并
        def merge(nums,left,mid,right):
            i=left
            j=mid+1  #分别用两个指针i和j
            temp=[]
            while i <= mid and j <= right:
                if nums[i] <= nums[j]:
                    temp.append(nums[i])
                    i += 1
                else:
                    self.count += mid - i + 1
                    temp.append(nums[j])
                    j += 1
            #左边数组没有遍历完,添加到数组中
            if i<=mid:
                temp.extend(nums[i:mid+1])
            #右边没有遍历完,添加过来
            else:
                temp.extend(nums[j:right+1])
            nums[left:right+1]=temp[:]
        mergesort(nums,0,len(nums)-1)
        return self.count

题目二:

给定一个数组 nums 和滑动窗口的大小 k,请找出所有滑动窗口里的最大值。

示例:

输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
输出: [3,3,5,5,6,7] 
解释: 

  滑动窗口的位置                最大值
---------------               -----
[1  3  -1] -3  5  3  6  7       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7

思路:如果直接循环加切片进行滑动窗口的话,数组过大还是会造成时间复杂度过高,不能通过。这里采用一个单调的数组,数组中是添加新的元素,并且完成删除要删除的窗口元素。这里加了一个判断,就是向队列中添加元素的时候,判断一下前面的元素和添加的元素的大小关系,如果比要添加的元素小的话,那就把队列中比它小的部分全部都删除。另外还要判断窗口中删除的元素和队首元素是否相等,相等的话也要将队首元素删除。

这里分为两个循环判断,第一个是形成窗口之前,第二个是形成窗口之后。

代码:

class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        #使用单调队列不停的删除元素,使队列的头元素就是最大的
        #特殊情况的判断
        if not nums or k == 0: return []
        queue=collections.deque()
        res=[]
        #第一部分计算的是i还没有形成窗口的时候,假如窗口大小是3,现在就是第1、2个元素的时候
        for i in range(0,k):
            #如果添加的元素大于现在队列中的元素,就将队列中小于要添加元素的元素删除
            while queue and queue[-1]<nums[i]:
                queue.pop()
            queue.append(nums[i])
        res.append(queue[0])
        #第二部分是形成窗口的时候,从开始形成窗口到最后
        for i in range(k,len(nums)):
            #首先要判断要从窗口中删除的元素是否等于队列中的首个元素
            #只判断队首元素是因为假设一个3大小的窗口,现在要删除的是数组中的第一个,第一个进去的元素如果是这三个的最大值,那它就会在开头,而我们现在要去除的就是第一个元素;如果它不是最大,那它已经被删除了,也就不重要,所以这里我们只要判断队首元素
            #nums[i-j]表示的是第一个进窗口的元素
            if queue[0]==nums[i-k]:
                queue.popleft()
            while queue and queue[-1]<nums[i]:
                queue.pop()
            queue.append(nums[i])    
            res.append(queue[0])
        return res

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值