算法练习Day2 (Leetcode/Python-数组/双指针)

数组专题2 


977. Squares of a Sorted Array 有序数组的平方 (双指针法)

Example:

Input: nums = [-4,-1,0,3,10]
Output: [0,1,9,16,100]
Explanation: After squaring, the array becomes [16,1,0,9,100].
After sorting, it becomes [0,1,9,16,100].

思路:

原数组是有排序的,从左到右从小到大。但是小的有可能是负数,负数的平方可能大于数组中正数的平方。但无论如何,中间的数的平方会小于两端的数的平方。考虑用双指针,一头一尾记录当前元素的位置并判断他们的值。

Solution:双指针法

class Solution(object):
    def sortedSquares(self, nums):
        """
        :type nums: List[int]
        :rtype: List[int]
        """
        left, right = 0, len(nums)-1
        output = [0] * (right+1) # 也可以用 []初始化,然后append添加元素,这样省去idx
        idx = len(nums)-1 
        nums_square = [i**2 for i in nums]
        while left <= right:
            if nums_square[left] > nums_square[right]:
                output[idx] = nums_square[left]
                left += 1
            else:
                output[idx] = nums_square[right]
                right -= 1
            idx -= 1
        return output

Time complexity: O(n)

Space complexity: O(1)

类似题目: 360. Sort Transformed Array

思路概述:此题的变化是把f(x) = x*2 改成了更有一般性的f(x)=ax^2+bx+c。其实只要判断一下a>0 还是a<0来判断数组两头的f(x) 是会出数组f(x)的最小值还是最大值就可以了。 

209. Minimum Size Subarray Sum (双指针动态窗口法)

Example
Input: target = 7, nums = [2,3,1,2,4,3]
Output: 2
Explanation: The subarray [4,3] has the minimal length under the problem constraint.

思路:

使用动态窗口。这也是双指针法之一。题目要求求得满足和大于target的最短连续数组的长度。从左到右遍历每个元素,右指针记录这个数组的右边界,左指针则是左边界。当sum>=target时,记录长度,同时从左侧去掉元素。当sum<target时,从右侧加入元素,使得重新满足条件。

注意!Corner case,没有满足要求的subarray,根据题目要求 return 0。

注意!使用While,不是if,向右一直挪动右指针直到满足sum的条件,再开始从左边减去直到不满足。

Solution:动态窗口法

class Solution(object):
    def minSubArrayLen(self, target, nums):
        """
        :type target: int
        :type nums: List[int]
        :rtype: int
        """
        left, right = 0, 0
        max_idx = len(nums)
        min_len = max_idx+1 #此为 len(nums)+1,大于有效的最小长度,用于判断是否return 0 
        cur_sum = 0 
        while right<max_idx:
            #right = right + 1 # 注意right应该在循环的最后更新
            cur_sum += nums[right]
            # 一旦达到sum>=target的目标,就可以计算现有有效subarray的长度,并且逐渐从左侧挪除元素。
            # 若挪出后sum<target, right指针不断加1,直到又满足目标,进入if循环。
            while cur_sum >= target: #用while不用if,直到不满足条件了才会向右挪动指针添加新的数
                min_len = min(min_len, right - left + 1)
                cur_sum -= nums[left]
                left += 1
            right += 1

        return min_len if min_len != len(nums)+1 else 0 # 有效的min_len不可能还保留初始值 

Time complexity: O(n)

Space complexity: O(1)

59. Spiral Matrix II(直接模拟法)

Example:

Input: n = 3
Output: [[1,2,3],[8,9,4],[7,6,5]]

思路:

输出的数组按照从左到右,从上到下,从右到左,再从下到上的顺序,一层一层往矩阵中心卷。用一个参数记住现在卷的是第几层,然后就按照卷的方向顺序向数组内填入值即可。写的时候采用两重循环嵌套,第一重是“当前卷到第几层了”。由于对于每一层,各边长的长度是相等的且可由第一重循环的值推导出来(比如例子中n=3,除去中心另外处理,就只卷一层。卷这一层的时候,每边的边长是2)。第二重循环是“当前卷到这一层某边长的哪个位置了。”,对于四条边长,写四个循环就好。

注意!处理好边界。比如range(1,4), 取到的值实际是1,2,3。

注意!对于n为奇数的时候,最中心的值就不循环四条边填满了,只有一个值,就作为corner case另外填进去吧。

Solution: 直接模拟法

class Solution(object):
    def generateMatrix(self, n):
        """
        :type n: int
        :rtype: List[List[int]]
        """
        nums = [[0] * n for _ in range(n)] # 生成一个n*n的matrix
        startx,starty = 0,0
        loop,mid = n//2, n//2
        count = 1

        for offset in range(1, loop + 1):
            for i in range(starty, n-offset):
                nums[startx][i] = count
                count += 1
            for i in range(startx, n-offset):
                nums[i][n-offset] = count
                count += 1
            for i in range(n-offset, starty, -1):
                nums[n-offset][i] = count
                count += 1
            for i in range(n-offset, startx, -1):
                nums[i][starty] = count
                count += 1
            startx += 1
            starty += 1
        
        if n % 2 != 0:
            nums[mid][mid] = count
        return nums 

Tips:   生成一个二维list可以这么写:nums = [[0] * n for _ in range(n)] # 生成一个n*n的matrix

range(n-offset, startx, -1),间隔为1逆序输出。这两种语法平时我写得不多,这里记录一下。

算法复杂度:O(n^2). 我差点想当然写成O(n), 才反应过来比如n=3,被卷的数列长度是n^2=9,所以是O(n^2).

空间复杂度:O(1)。看别的帖子,在算空间复杂度的时候不算output所占用空间,只考虑算法涉及的额外的占用。

个人关于数组的小结:

以上五道题使用了双指针(单向/双向)、滑动窗口、二分法、直接模拟法。二分法使用了一种分而治之、迭代循环的思想。双指针通常涉及两个值/位置的定位、比较、判断。滑动窗口根本上感觉也算是双指针。

Reference: 

代码随想录

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值