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

977.有序数组的平方(easy)

力扣链接
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

思路1 暴力求平方然后排序

直接使用python的sorted()函数。

class Solution(object):
    def sortedSquares(self, nums):
        """
        :type nums: List[int]
        :rtype: List[int]
        """
        new_nums = []
        for i in range(len(nums)):
            new_nums.append(nums[i]*nums[i])
        new_nums = sorted(new_nums)
        return new_nums

思路2 相向而行双指针

由于数组是非降序的,因此平方越大的值应该越靠近两端,不妨令两个指针一前一后筛查最大平方项,找到了就把他扔到新数组里面。又由于要求结果也要非降序,因此要从后往前放。
python创建全0数组:new_nums = len(nums)*[0]

class Solution(object):
    def sortedSquares(self, nums):
        """
        :type nums: List[int]
        :rtype: List[int]
        """
        new_nums = len(nums)*[0]
        j = k = len(nums)-1 # j指向原数组的末尾,k指向新数组的末尾
        i = 0 #头指针,指向原数组的开头
        while i<=j:
            print(i,j)
            if(nums[i]*nums[i] < nums[j]*nums[j]): 
            #如果左边的小,则把右边的结果放到新数组k位置,并把j左移一位
                new_nums[k] = nums[j]*nums[j]
                j -= 1
            else:
            #如果左边的大,则把左边的结果放到新数组k位置,并把i右移一位
                new_nums[k] = nums[i]*nums[i]
                i += 1
            k -= 1
        return new_nums

209.长度最小的子数组(normal)

力扣链接
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。

思路1. 暴力解法

搞两层循环,一个个去比较,但很可惜这个方法在处理长输入时力扣会判定超时

class Solution(object):
    def minSubArrayLen(self, target, nums):
        """
        :type target: int
        :type nums: List[int]
        :rtype: int
        """
        ret_nums = nums  ## 用来记录最终返回的子序列
        temp_nums = []  ## 用来记录当前循环得到的子序列,每次循环都更新
        flag = False # 用来记录是否能找到子序列
        for i in range(len(nums)):
            num_sum = 0
            j = i
            while j<=len(nums)-1:
                num_sum += nums[j]
                if num_sum >= target:  # 如果达成目的
                    flag = True
                    temp_nums = nums[i:j+1] # 取子序列,注意nums[,]是左闭右开的,要j+1
                    if len(ret_nums)>len(temp_nums):  
                    # 如果当前temp_nums长度更短则更新入ret_nums
                        ret_nums = temp_nums
                    break
                j += 1

        if flag == False:
            ret_nums = []
        

        return len(ret_nums)

思路2. 滑动窗口

为了方便说明,我们在此规定滑动窗口整体从左到右滑动,左端指针称为“左脚”,右端指针称为“右脚”,滑动窗口即为左右脚之间夹着的区间。
其实,思路1的暴力解法也可认为是一种滑动窗口,这种方法用了两个循环。外层循环规定左脚位置,内层循环规定右脚位置,左脚作为立足点,右脚反复地向前试探。这样的滑动窗口效率太低。
因此,不妨让左脚活动起来,及时跟进右脚的步伐,而右脚则一往无前。
滑动窗口法的步骤为:

  1. 首先,让右脚一步步往前迈,左脚不动,同时统计双脚之间的和。
  2. 当和满足条件时,记录当前窗口中的子序列。然后左脚往前迈,缩小窗口。
  3. 在被缩小的窗口内再判断是否满足条件,如果满足,回到2.如果不满足,则让右脚继续向前。
class Solution(object):
    def minSubArrayLen(self, target, nums):
        """
        :type target: int
        :type nums: List[int]
        :rtype: int
        """
        n_sum = 0 #窗口内和
        left = 0 # 窗口起始位置
        right = 0 #窗口终止位置
        temp_nums = []
        ret_nums = nums
        flag = False
        while right < len(nums):
            n_sum += nums[right]
            # 当没找到子序列时,不断地迈右脚并把最新纳入的元素加上去

            while n_sum >= target:
            # 当找到子序列时,把当前子序列记下来,并让左脚跟上
                flag = True
                temp_nums = nums[left:right+1] # 获取子序列
                n_sum -= nums[left] # 重新统计窗口内元素和
                if len(temp_nums)<len(ret_nums):
                    ret_nums = temp_nums
                
                left += 1
            
            right +=1
        
        if flag == False:
            ret_nums = []

        return len(ret_nums)

59.螺旋矩阵(normal)

力扣链接
给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。

思路

模拟顺时针画矩阵的过程:
填充上行从左到右
填充右列从上到下
填充下行从右到左
填充左列从下到上
在这里插入图片描述
而且每次循环的区间的开闭都要一致,这里采用左闭右开。
具体步骤如下:

  1. 首先定义几个重要的变量
    行坐标为x,列坐标为y
nums = [[0] * n for _ in range(n)] # 用来创建一个n*n的二维数组
loop = n/2  用来定义要套几圈,如果是偶数,会正好套完,如果是奇数,最后会在中间留一个顽固分子
mid = n/2 如果是奇数,最中间残留的位置为nums[mid][mid]
startx ,starty 每次套圈的起始位置,即左上角
count 要放的元素,让他每次+1即可自动地从1到n*n置入
offset 从1开始每套完一圈+1,用n-offset来表示当前最右边的纵坐标和最下边的横坐标 
  1. 写最上边
    最上边的行坐标恒为startx,列坐标从左到右,即starty→n-offset
  2. 写最右边
    最右边的列坐标恒为n-offset,行坐标从上到下,即从startx→n-offset
  3. 写最下边
    最下边的行坐标恒为n-offset,列坐标从左到右,即从n-offset→starty
  4. 写最左边
    最左边的列坐标恒为starty,行坐标从下到上,即从n-offset→startx
  5. 让起始位置偏移,进入下一次套圈
  6. 处理最中间的
class Solution(object):
    def generateMatrix(self, n):
        """
        :type n: int
        :rtype: List[List[int]]
        """
        nums = [[0] * n for _ in range(n)] # 构造一个n*n的二维数组
        loop = n/2 # 要转几圈 当n为奇数时,中间只有一个空,那就不必循环了,直接填充n*n
        mid = n/2 # 矩阵中间位置的横纵坐标
        startx = starty = 0 # 每次转圈的左上角起始位置
        count = 1
        for offset in range(1,loop+1): #要从1开始,1~loop 用offset来控制边长
        # n-offset表示当前最右边的纵坐标,最下边的横坐标
            # 上边
            for j in range(starty, n-offset): #左闭右开
                nums[startx][j] = count
                count += 1
            # 右边
            for i in range(startx, n-offset):
                nums[i][n-offset] = count
                count += 1
            # 下边
            for j in range(n-offset, starty, -1):
                nums[n-offset][j] = 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
        print(nums)
        return nums
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值