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

977. 有序数组的平方

题目链接 | 解题思路

题目的特点在于“有序”,所以双指针可以成为一个合格的解法。题目不难,但是要迅速意识到可以用双指针。
时间复杂度: O ( n ) O(n) O(n)

Naive的双指针(自己的解法)

  1. 找到正负号变换的 index(这一步其实可以省略)
  2. 从变换的 index 向两边同时查找,一次遍历,依次取得最小平方

问题在于写的丑陋,同时还需要最后的收尾(可以优化 while 的 termination condition?)

class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        results = []
        negative_count = 0
        for i in range(len(nums)):
            if nums[i] < 0:
                negative_count += 1
        
        if negative_count == 0:
            for i in range(len(nums)):
                results.append(nums[i] ** 2)
            return results
        else:
            negative_idx = negative_count - 1
            positive_idx = negative_count
            while (negative_idx >= 0 and positive_idx <= len(nums)-1):
                if nums[positive_idx] < -nums[negative_idx]:
                    results.append(nums[positive_idx] ** 2)
                    positive_idx += 1
                else:
                    results.append(nums[negative_idx] ** 2)
                    negative_idx -= 1
            for i in range(negative_idx, -1, -1):
                results.append(nums[i] ** 2)
            for i in range(positive_idx, len(nums)):
                results.append(nums[i] ** 2)

            return results

双向指针

左右各一个指针进行遍历,直接比较获得数组。
注意由于出现在两端的都是(平方)最大值,所以输出的数组应该从后往前更新。

class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        left_idx = 0
        right_idx = len(nums) - 1
        results = [0] * len(nums)

        i = len(nums) - 1
        while (left_idx <= right_idx):
            if nums[left_idx]**2 > nums[right_idx]**2:
                results[i] = nums[left_idx]**2
                left_idx += 1
            else:
                results[i] = nums[right_idx]**2
                right_idx -= 1
            i -= 1
        
        return results

创建长度为 n 的数组:a = [0] * n


209. 长度最小的子数组

题目链接 | 解题思路

处理滑动区间的基础方法,解题时需明确

  • 区间:某一段连续子数组(subarray),由left_idxright_idx标记起始
  • 何时改变区间首尾 index
    • 区间和 >= target:将区间起始向右移,尝试获得更小的区间是否同样能满足条件
    • 区间和 < target:将区间终点向右移,加入更多元素以满足条件

注意到暴力解法实质是对每一个区间起点left_idx都穷举right_idx,所以是 O ( n 2 ) O(n^2) O(n2)的复杂度。
滑动区间(特殊版本的双指针)利用了left_idx只会右移的特点,只遍历right_idx,得到了 O ( n ) O(n) O(n)的复杂度。

自己的解法(本质相同)

class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        best_length = len(nums) + 1
        curr_sum = 0
        left_idx = 0
        right_idx = -1

        while (right_idx < len(nums)):
            if curr_sum >= target:
                # update the window size if necessary
                best_length = min(right_idx - left_idx + 1, best_length)
                # to see whether a smaller window can also work
                curr_sum -= nums[left_idx]  
                left_idx += 1
            else:               # need more elements to meet target
                right_idx += 1
                if right_idx < len(nums): 
                    curr_sum += nums[right_idx]

        if best_length == len(nums) + 1:
            return 0
        return best_length

标准思路

class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        best_length = len(nums) + 1
        curr_sum = 0
        left_idx = 0

        for right_idx in range(len(nums)):
            curr_sum += nums[right_idx]
            while (curr_sum >= target):     # notice that use "while" to go over all the subarrays with current right_idx
                best_length = min(best_length, right_idx - left_idx + 1)
                curr_sum -= nums[left_idx]
                left_idx += 1
        
        if best_length == len(nums) + 1:
            return 0
        return best_length

904. 水果成篮

题目链接


74. 最小覆盖子串

题目链接


59. 螺旋矩阵II

题目链接 | 解题思路

这道题没有复杂的算法思路,本质是能分清楚循环中每个 case 的边界条件,考验思路是否清晰 + 能否实现。

Recursion

暴力解法,直接通过 recursion 得到 n − 2 n-2 n2 的矩阵,然后手动加上最外面的一圈

class Solution:
    def generateMatrix(self, n: int) -> List[List[int]]:
        if n == 1:
            return [[1]]
        if n == 2:
            return [[1, 2],
                    [4, 3]]
        
        temp_results = self.generateMatrix(n - 2)
        results = []
        
        first_line = []
        for i in range(n):
            first_line.append(i+1)
        last_line = []
        for i in range(3*n-2, 2*n-2, -1):
            last_line.append(i)

        results.append(first_line)
        for i in range(1, n-1):
            temp = [4*(n-1) - i + 1]
            for j in range(1, n-1):
                temp.append(temp_results[i-1][j-1] + 4*(n-1))
            temp.append(n+i)
            results.append(temp)
        results.append(last_line)

        return results

Naive 解法

主要的难点在于每个变量对应的含义以及边界条件:

  • loop_offset:记录当前在整个矩阵第几圈(自外而内)
  • curr_row, curr_col:记录当前元素的行和列,注意要在每个 outer while iteration 开始时设置为对应的loop_offset
  • counter:记录当前填入的值是多少
class Solution:
    def generateMatrix(self, n: int) -> List[List[int]]:
        results = [[0] * n for i in range(n)]
        loop_offset = 0     # denote which loop around the square we are at
        curr_row = curr_col = 0         
        counter = 1         # record which value to fill in

        while (loop_offset < n//2):
            curr_row = curr_col = loop_offset

            # first fraction: upper
            for j in range(loop_offset, n - loop_offset - 1):        # not include the last element in this row
                results[curr_row][j] = counter
                counter += 1
                curr_col += 1
                print(curr_row)
            # curr_col = n - loop_offset - 1
            # second fraction: right
            for i in range(loop_offset, n - loop_offset - 1):        
                results[i][curr_col] = counter
                counter += 1
                curr_row += 1
            # curr_row = n - loop_offset - 1
            # third fraction: below
            for j in range(n - loop_offset - 1, loop_offset, -1):
                results[curr_row][j] = counter
                counter += 1
                curr_col -= 1
            # curr_col = 0
            # last fraction: left
            for i in range(n - loop_offset - 1, loop_offset, -1):
                results[i][curr_col] = counter
                counter += 1
                curr_row -= 1
            # curr_row = 0

            loop_offset += 1
        
        if n % 2:
            results[loop_offset][loop_offset] = n**2
        
        return results

创建一个2d数组:results = [[0] * n for i in range(n)]
不要使用results = [[0] * n] * n,会有 copy 的问题

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值