代码随想录算法训练营第二天| 977.有序数组的平方 、 209.长度最小的子数组、59.螺旋矩阵II

Leetcode - 977

这题需要的时间复杂度是0(n) 因此不能按照先平方再排序的暴力解法做,对于O(n)的题,要么二分要么双指针。显然 这里是用双指针

由于数组可能是从负数到正数由小到大排列的,所以平方之后最大元素在两侧,越往中间走值越小,所以可以自定义一个结果数组,和两个指针分别指向原数组的一头一尾,比较指针指向的两个下标对应的元素,比较元素的大小,将较大的那一个放入结果数组的尾部,指针再移动(向前一个后者向后一个),依次将结果从结果的数组的尾部到头部填充。

 def sortedSquares(nums: List[int]) -> List[int]:
        res = [0] * len(nums)
        init = len(nums)-1

        i = 0
        j = len(nums)-1
        nums = [p ** 2 for p in nums]
        while i<= j:
            if nums[i] >= nums[j]:
                res[init] = nums[i]
                i+=1
            else:
                res[init] = nums[j]
                j-=1
            init -=1
        
        return res

Leetcode - 209

典型的滑动窗口题,两个指针没跑了。定义一个结果的初始大小,这个初始大小的值一定要大于数组的长度,快指针先向前移动,直到慢指针和快指针所囊括的区间和sum的大小大于等于target, 然后开始缩减窗口的大小,缩减窗口这里要注意:先更新结果的大小,然后窗口从左到右缩进一格,sum减去慢指针指向的元素值,然后慢指针++,最后判断结果是否等于初始大小,若仍等于则说明数组不满足条件,不等于就返回这个结果

def minSubArrayLen(target: int, nums: List[int]) -> int:
        if len(nums) == 1:
            if nums[0] >= target:
                return 1
            else:
                return 0

        i = 0
        sum = 0
        res = len(nums)+1
        for j in range(len(nums)):
            sum += nums[j]
            while sum >= target:
                res = min(res,j-i+1)
                sum -= nums[i]
                i+=1

        return 0 if res == len(nums)+1 else res

这里巧妙的一点是,区间和的大小不是去计算一个区间内所有元素和,而是一开始就设定快指针为循环的元素,从0开始出发,不断累加

Leetcode - 56

这题最重要的就是要搞清边界条件,到底要转几圈,n为奇数还是偶数有啥区别,每条边要循环时要怎么处理?

代码随想录算法训练营第二天| 977.有序数组的平方 、 209.长度最小的子数组、59.螺旋矩阵II_第1张图片

 循环的时候 最重要的一点就是 左闭右开原则,也就是每次遍历都留最边上的那个值不遍历,下一条边遍历的时候就从这个边界值出发,很显然,每次循环的时候,这个边界值的位置都不同,比如第一次循环的时候,边界为每条边最后一个元素,但是第二次循环的时候这个边界值就是每条边倒数第二个元素,所以要定义一个值来记录这个值。

关于循环,观察可知循环次数为n//2,若n为奇数则中间那个值没法遍历到,可在最后对中间的那个值进行赋值为n²

每一圈循环的起点不同,比如第一个起点是(0,0),那么第二循环的起点就是(1,1),...

def generateMatrix( n: int) -> List[List[int]]:

        res = [[0]*n for i in range(n)]

        #初始坐标位置
        startX = 0
        startY = 0

        #初始边界条件,满足左闭右开原则
        offset = 1
        
        number = 1
        #初始数值
#  第一条边,从左到右,横坐标不变,所以横坐标是startX, 纵坐标用于遍历,从startY开始
        for _ in range(n // 2):
            for i in range(startY,n-offset):
                res[startX][i] = number
                number += 1
    #第二条边,从上到下,纵坐标不变,纵坐标为刚才遍历后的结果的下一个位置,及边界位置n-offset
    # 从横坐标开始遍历即startX      
            for i in range(startX,n-offset):
                res[i][n-offset] = number
                number += 1
     # 第三条边,从左到右,横坐标不变,及边界值n-offset,纵坐标用于遍历,从边界值n-offset出发,
# 遍历直到startY前一个值为止,这里是逆向遍历       
            for i in range(n-offset,startY,-1):
                res[n-offset][i] = number
                number += 1
      #第四条边,从下到上,纵坐标不变,为边界值startY,横坐标用于遍历,从边界值n-offset出发,
# 遍历直到startX的前一个值,依旧是逆向,步长为-1     
            for i in range(n-offset,startX,-1):
                res[i][startY] = number
                number += 1
            
            startX += 1
            startY += 1
            offset +=1

        if n %2 !=0:
            res[n//2][n//2] = number

        return res

你可能感兴趣的:(算法,python)