LeetCode刷题小记 一、【数组】

这篇具有很好参考价值的文章主要介绍了LeetCode刷题小记 一、【数组】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

LeetCode刷题小记 一、【数组】

写在前面

本系列笔记主要作为笔者刷题的题解,所用的语言为Python3,若于您有助,不胜荣幸。

1. 数组

1.1 理论基础

数组[array]是一种线性的数据结构,将相同的数据类型存储在连续的内存空间当中,我们将元素在数组中的位置称为该元素的索引[index]。由于数组是连续存储的特性,我们访问其中单个元素变得十分容易,我们只需要知道其索引就能访问其中的元素,索引本质上是内存地址的偏移量

由于数组中元素的连续存在的,因此要在数组中插入、删除元素,需要移动后续的所有元素。所以数组的各项操作的时间复杂度如下

Operation Time Complexity
插入、删除 O ( n ) \mathcal{O}(n) O(n)
查找 O ( 1 ) \mathcal{O}(1) O(1)

1.2 二分查找

704二分查找

二分查找的前提是有序数组(升序或者降序),且无重复元素

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

二分查找的第一种写法是要定义在一个左闭右闭的区间里,[left, right],所以终止条件就可以写为:while (left <= right)

class Solution:
    def search(self, nums: List[int], target: int) -> int:

        left: int = 0
        right: int = len(nums) - 1	#左闭右闭
        
        while left <= right:
            mid: int = (left + right) // 2
            if target > nums[mid]:
                left = mid + 1
            elif target < nums[mid]:
                right = mid - 1
            else:
                return mid
        return -1
  • 时间复杂度: O ( log ⁡ n ) \mathcal{O}(\log n) O(logn)
  • 空间复杂度: O ( 1 ) \mathcal{O}(1) O(1)

第二种写法是将其定义在一个左闭右开的区间,[left, right)当中,所以终止条件必须写为:while (left < right)

class Solution:
    def search(self, nums: List[int], target: int) -> int:

        left: int = 0
        right: int = len(nums)	#左闭右开
        
        while left < right:
            mid: int = left + (right - left) // 2
            if target > nums[mid]:
                left = mid + 1
            elif target < nums[mid]:
                right = mid
            else:
                return mid
        return -1

35搜索插入位置

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        left: int = 0
        right: int = len(nums)-1
        while left <= right:
            mid = left + (right - left) // 2
            if nums[mid] > target:
                right = mid - 1
            elif nums[mid] < target:
                left = mid + 1
            else:
                return mid
        return left

34在排序数组中查找元素的第一个和最后一个位置

# 1、首先,在 nums 数组中二分查找 target;
# 2、如果二分查找失败,则 binarySearch 返回 -1,表明 nums 中没有 target。此时,searchRange 直接返回 {-1, -1};
# 3、如果二分查找成功,则 binarySearch 返回 nums 中值为 target 的一个下标。然后,通过左右滑动指针,来找到符合题意的区间
class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        def binarySearch(nums: List[int], target: int) -> int:
            left: int = 0
            right: int = len(nums) - 1
            while left <= right:
                mid = left + (right - left) // 2
                if nums[mid] > target:
                    right = mid - 1
                elif nums[mid] < target:
                    left = mid + 1
                else:
                    return mid
            return -1
        
        index = binarySearch(nums, target)

        if index == -1: return [-1, -1]
        left = right = index
        while left - 1 >= 0 and nums[left - 1] == target: left -= 1
        while right + 1 <= len(nums) - 1 and nums[right+1] == target: right += 1
        return [left, right]

69x的平方根

class Solution:
    def mySqrt(self, x: int) -> int:
        if x == 0 or x == 1:
            return x
        left: int = 1
        right: int = x
        res: int = -1
        while left <= right:
            mid = left + (right - left) // 2
            if mid * mid <= x:  # 平方更要小于等于当前的x所以,这里用<=来限制区间
                res = mid
                left = mid + 1
            else:
                right = mid - 1
        return res

367有效的完全平方数

class Solution:
    def isPerfectSquare(self, num: int) -> bool:
        left: int = 1
        right: int = num
        while left <= right:
            mid = left + (right - left)//2
            if mid * mid > num:
                right = mid - 1
            elif mid * mid < num:
                left = mid + 1
            else:
                return True
        return False

1.3 移除元素

27移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。

可以使用双指针法:通过一个快指针和慢指针在一个for循环中完成两个for循环的工作。

定义快慢指针

  • 快指针:寻找新数组的元素,新数组就是不含有目标元素的数组,如果快指针指向的元素不等于val,那么它一定是输出数组中的元素,所以将其赋值给慢指针的位置
  • 慢指针:指向更新,新数组的下标位置,如果快指针指向的元素等于val,说明它不是输出数组中的元素,我们直接移动快指针即可

双指针的方法,在处理数组和链表的操作当中都是非常常见的。

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        slowIndex: int = 0
        for fastIndex in range(len(nums)):
            if nums[fastIndex] != val:
                nums[slowIndex] = nums[fastIndex]
                slowIndex += 1
        return slowIndex

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        slowIndex: int = 0
        fastIndex: int = 0
        while fastIndex < len(nums):
            if nums[fastIndex] != val:
                nums[slowIndex] = nums[fastIndex]
                slowIndex += 1
            fastIndex += 1
        return slowIndex

26删除有序数组中的重复项

class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        fastIndex: int = 1
        slowIndex: int = 0
        while fastIndex <= len(nums) - 1:
            if nums[slowIndex] == nums[fastIndex]:
                fastIndex += 1
            elif nums[slowIndex] != nums[fastIndex]:
                slowIndex += 1
                nums[slowIndex] = nums[fastIndex]
        return slowIndex + 1

283移动零

class Solution:
    def moveZeroes(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        slowIndex: int = 0
        fastIndex: int = 0
        while fastIndex <= len(nums) - 1:
            if nums[fastIndex] != 0:
                nums[slowIndex] = nums[fastIndex]
                slowIndex += 1
            fastIndex += 1

        for i in range(slowIndex, fastIndex):
            nums[i] = 0

1.4 有序数组的平方

977有序数组的平方

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

思路,该数组已经知道为有序数组,那么数组的中间值的平方一定是最小的,最大值一定是从两侧值的平方中进行选取,所以我们可以使用左右指针开始查找。

class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        leftIndex: int = 0
        rightIndex: int = len(nums) - 1
        resIndex: int = len(nums) - 1
        res: List[any] = [float('inf')] * len(nums)

        while leftIndex <= rightIndex:
            elem1 = nums[leftIndex] ** 2
            elem2 = nums[rightIndex] ** 2
            if elem1 >= elem2:
                res[resIndex] = elem1
                leftIndex += 1
            else:
                res[resIndex] = elem2
                rightIndex -= 1
            resIndex -= 1
        return res

1.5 长度最小的子数组

209长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 target

找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度**。**如果不存在符合条件的子数组,返回 0

本题采用的思想是,滑动窗口,滑动窗口可以分为最大滑动窗口和最小滑动窗口,具体的区别在于最大滑动窗口目的在于最大化满足条件的区间长度,而最小化滑动窗口目的在于最小化满足条件的区间长度。

最小滑窗模板:给定数组 nums,定义滑窗的左右边界 i, j,求满足某个条件的滑窗的最小长度。

while j < len(nums):
    判断[i, j]是否满足条件
    while 满足条件:
        不断更新结果(注意在while内更新!)
        i += 1 (最大程度的压缩i,使得滑窗尽可能的小)
    j += 1

最大滑窗模板:给定数组 nums,定义滑窗的左右边界 i, j,求满足某个条件的滑窗的最大长度。

while j < len(nums):
    判断[i, j]是否满足条件
    while 不满足条件:
        i += 1 (最保守的压缩i,一旦满足条件了就退出压缩i的过程,使得滑窗尽可能的大)
    不断更新结果(注意在while外更新!)
    j += 1
class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        startIndex: int = 0
        result: any = float('inf')
        s: int = 0
        for endIndex in range(len(nums)):
            s += nums[endIndex]
            while s >= target:
                result = min(result, endIndex - startIndex + 1)
                s -= nums[startIndex]
                startIndex += 1
        return result if result != float('inf') else 0

defaultdict的用法

python中的defaultdictcollections库中的一种字典,与python中默认字典dict的区别在于,我们可以指定defaultdict当访问到不存在的key是的返回值,比如

from collections import defaultdict
d1 = defaultdict(int)		#设置d1访问不存在的key时返回0
d2 = defaultdict(list)		#设置d2访问不存在的key时返回空列表[]
d2 = defaultdict(bool)		#设置d3访问不存在的key时返回False
print(d1['a'])
print(d2['a'])
print(d3['a'])

返回的结果为

0
[]
False

904. 水果成篮

class Solution:
    def totalFruit(self, fruits: List[int]) -> int:
        left: int = 0
        right: int = 0
        result: int = 0
        classMap: dict = defaultdict(int)      #访问不存在的key返回0
        classCnt: int = 0

        while right <= len(fruits) - 1:
            # 判断是否满足情况
            if classMap[fruits[right]] == 0:
                classCnt += 1
            classMap[fruits[right]] += 1
            
            # 当不满情况的时候才对left进行移动,这样能够保证滑动窗口为最大
            while classCnt > 2:
                if classMap[fruits[left]] == 1:
                    classCnt -= 1
                classMap[fruits[left]] -= 1 
                left += 1
                
            # 结果在外面进行更新
            result = max(result, right - left + 1)
            right += 1
        return result

76. 最小覆盖子串

给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 ""

class Solution:
    def minWindow(self, s: str, t: str) -> str:
        left: int = 0
        right: int = 0
        strMap: dict = collections.defaultdict(int)   #访问不存在的key时返回0
        strCnt: int = len(t)
        result: str = ''

        for char in t:
            strMap[char] += 1
        
        # 移动右边界
        while right <= len(s) - 1:
            # 判断当前字母是否被需要
            if s[right] in strMap:
                if strMap[s[right]] > 0:
                    strCnt -= 1
                strMap[s[right]] -= 1
            
            # 压缩左边界
            while strCnt == 0:
                # 更新result
                if not result or right - left + 1 < len(result):
                    result = s[left: right + 1]

                # 判断当前字母是否可压缩
                if s[left] in strMap:
                    if strMap[s[left]] == 0:
                        strCnt += 1
                    strMap[s[left]] += 1
                left += 1
            right += 1
        return result

1.6 螺旋矩阵II

59. 螺旋矩阵 II

给你一个正整数 n ,生成一个包含 1n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix

这道题的重点在于确定循环不变量,我们要保证每次循环的写法的区间都具有一致性,所以我们在这里采用左闭右开的方式来进行循环。

class Solution:
    def generateMatrix(self, n: int) -> List[List[int]]:
        nums: List[List[int]] = [[0] * n for _ in range(n)]
        startx: int = 0
        starty: int = 0
        loop: int = n // 2
        count: int = 1
        offset: int = 1
        for _ in range(loop):
            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
            offset += 1
        
        if n % 2 == 1:
            nums[n // 2][n // 2] = count
        return nums

54. 螺旋矩阵

给你一个 mn 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。

class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        m: int = len(matrix)
        n: int = len(matrix[0])
        loop: int = min(m, n) // 2
        print(loop)
        startx: int = 0
        starty: int = 0
        offset: int = 1
        res: List[int] = []

        for _ in range(loop):
            for j in range(starty, n - offset):
                res.append(matrix[startx][j])
            for i in range(startx, m - offset):
                res.append(matrix[i][n - offset])
            for j in range(n - offset, starty, -1):
                res.append(matrix[m - offset][j])
            for i in range(m - offset, startx, -1):
                res.append(matrix[i][starty])
            startx += 1
            starty += 1
            offset += 1
        
        if min(m, n) % 2 == 1:
            if m <= n:
                for j in range(starty, n - (offset-1)):   #注意这里转完一圈之后offset实际上是被+1了,我们需要还原上一圈中的offset
                    res.append(matrix[startx][j])
            else:
                for i in range(startx, m - (offset-1)):
                    res.append(matrix[i][starty])
        return res

Reference

[1] Hello 算法
[2] 代码随想录文章来源地址https://www.toymoban.com/news/detail-825567.html

到了这里,关于LeetCode刷题小记 一、【数组】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • LeetCode刷题(ACM模式)-01数组

    LeetCode刷题(ACM模式)-01数组

    参考引用:代码随想录 注:每道 LeetCode 题目都使用 ACM 代码模式,可直接在本地运行,蓝色字体为题目超链接 0. 数组理论基础 数组( array )是 存放在连续内存空间上的相同类型数据的集合 ,是一种 复合数据类型 ,它是 有序数据的集合 ,在存储空间中也是按顺序存储。数

    2024年02月11日
    浏览(206)
  • LeetCode刷题系列之《双指针解数组》

    LeetCode刷题系列之《双指针解数组》

    各位csdn的友友们好啊,今天阿博给大家分享几道leetcode上的经典数组题,通过这次的学习,相信友友们可以更全面的认识指针和数组🍉🍉🍉 一.题目描述 给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。

    2023年04月26日
    浏览(43)
  • 【LeetCode刷题(数组and排序)】:存在重复元素

    【LeetCode刷题(数组and排序)】:存在重复元素

    给你一个整数数组 nums 。如果任一值在数组中出现 至少两次 ,返回 true ;如果数组中每个元素互不相同,返回 false 示例 1: 输入:nums = [1,2,3,1] 输出:true 示例 2: 输入:nums = [1,2,3,4] 输出:false 示例 3: 输入:nums = [1,1,1,3,3,4,3,2,4,2] 输出:true 在对数字从小到大排序之后,数

    2024年02月07日
    浏览(40)
  • Leetcode刷题详解——长度最小的子数组

    Leetcode刷题详解——长度最小的子数组

    给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度**。**如果不存在符合条件的子数组,返回 0 。 示例 1: 示例 2: 示例 3: 提示: 1 = target = 109 1 = nums.length

    2024年02月07日
    浏览(38)
  • LeetCode 刷题 数据结构 数组 485 最大连续1的个数

    LeetCode 刷题 数据结构 数组 485 最大连续1的个数

    给定一个二进制数组  nums  , 计算其中最大连续  1  的个数。 示例 1: 示例 2: 提示: 1 = nums.length = 105 nums[i]  不是  0  就是  1.   参看bilibli视频-up主 爱学习的饲养员,讲解的很清晰。 手把手带你刷Leetcode力扣|各个击破数据结构和算法|大厂面试必备技能【已完结】-

    2024年02月15日
    浏览(35)
  • LeetCode刷题集(三)(26 删除有序数组中的重复项)

    LeetCode刷题集(三)(26 删除有序数组中的重复项)

    基本掌握LeetCode中的26删除有序数组中的重复项 题目描述: 给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。 由于在某些语言中不能改变数组的长度,所以必须将结果放

    2023年04月17日
    浏览(35)
  • leetcode分类刷题:哈希表(Hash Table)(一、数组交集问题)

    1、当需要快 速判断某元素是否出现在序列中 时,就要用到哈希表了。 2、本文针对的总结题型为给定 两个及多个数组 ,求解它们的 交集 。接下来,按照由浅入深层层递进的顺序总结以下几道题目。 3、以下题目需要共同注意的是:对于两个数组,我们总是尽量把短数组转

    2024年02月11日
    浏览(6)
  • 【Leetcode刷题-Python/C++】长度最小的子数组(滑动窗口)

    209.长度最小的子数组 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。 输入:target = 7, nums = [2,3,1,2,4,3] 输出:2 解释:子数

    2023年04月08日
    浏览(6)
  • 老卫带你学---leetcode刷题(215. 数组中的第K个最大元素)

    给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。 请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。 你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。 堆排序 对每个元素入堆,然后pop出来k-1个 这里需要注意,默认堆为最

    2024年02月07日
    浏览(9)
  • leetcode算法刷题——链表

    题意:删除链表中等于给定值 val 的所有节点。 示例 1: 输入:head = [1,2,6,3,4,5,6], val = 6 输出:[1,2,3,4,5] 示例 2: 输入:head = [], val = 1 输出:[] 示例 3: 输入:head = [7,7,7,7], val = 7 输出:[] 在链表类中实现这些功能: get(index):获取链表中第 index 个节点的值。如果索引无效,

    2024年02月21日
    浏览(8)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包