力扣数组篇——代码随想录

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

目录

一、介绍数组

二、题目分析与心得

总结



一、介绍数组

1.什么是数组呢?

        数组是最常见的数据结构,用来存储数据,只具有数据域。

2.数组的类别

        我们常见的数组通常由以下几种:

                一维数组:具体表现形式为  a = {1, 2, 3, 4, 5},该数组的长度为5,下标为0,1,2,3,4(一定注意数组的下标从0开始)。当我们要访问数据2的时候,通过a[1]访问。

                二维数组:具体表现形式为 b = {{0, 1, 2},

                                                                    {3, 4, 5},

                                                                    {6, 7, 8}}

                                        这样看的话可能更容易理解,可以把二维数组当成若干个一维数组,当我们想要访问5的时候,通过b[1][2]访问

                    更高维度的数组此处不在介绍,可以通过二维数组是若干个一维数组的组合来以此类推。

3.数组的特点

        数组和链表我们通常放在一起对比,上一篇文章也已经提到了,数组的连续存储的,因此我们可以通过下标来进行访问,这也导致了它的一些优点和缺点。(可以和链表的对应起来看)

        优点:

                (1)地址连续,所以我们可以通过下标访问,也就是随机存取,比如我们想要访问数组的第n个位置元素,则可以直接通过a[n-1]访问,注意数组下标从0开始。

                (2)所有的空间都用来存储数据,所以空间利用率为100%

        缺点:

                (1)因为地址空间要求连续,所以我们必须要找到一片连续的空间来存储数组,内存中的碎片空间利用不充分。

                (2)同样因为地址空间要求连续,导致了我们对数组当中元素进行增删的时候,要移动大量元素,比如一个长度为5的数组,我们要把第二个位置的元素删除,则我们就需要依次把三位置覆盖二位置,四位置覆盖三位置,五位置覆盖四位置。想要增加元素同理,而且数组一旦创建,长度就确定了,不能增加了减少,所以当数组已满的时候,如果我们想要再增加元素,就需要从新创建一个更大的数组,然后依次把原有的元素移动过去,之后再插入新元素。

二、题目分析与心得

(1).

704.二分查找

分析:读题时需要着重注意到一点,有序,此时我们就需要考虑二分法,如果想到了这点,则此题很容易解出,不过使用二分法的时候,一定要注意左右两边区间的开闭和循环条件中是否取等的关系。

代码实现

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

心得:二分法是求解数组问题中非常非常常用的方法,但要注意几个要点,数组是否有序,区间的开闭,循环条件是否取等

下面的一些题目可以作为对二分法的练习

35.搜索插入位置       

 34.在排序数组中查找元素的第一个位置和最后一个位置(此题较难,着重考察了对左右区间,循环条件的判断)

69.x的平方根

367.有效的完全平方数


(2).

27.移除元素

分析:此题的思路为使用快慢指针,慢指针用来指向需要保留数组位置的下一个位置,快指针从头开始遍历,指向要判断元素的位置,难点在于对if内外的代码书写,要注意,如果元素要保留的话,就让快指针指向的覆盖慢指针指向的,假如这时候快慢指针位置相同,则没有什么影响,如果不同,也没有关系,因为慢指针指向的一定是需要移除的元素,具体自己可以画图分析一下

代码实现:

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

心得:数组中快慢指针的应用!!!

数组中快慢指针相关题目练习

26. 删除有序数组中的重复项 - 力扣(LeetCode)

283. 移动零 - 力扣(LeetCode)

844. 比较含退格的字符串 - 力扣(LeetCode)此题思路比较难想


(3).

977. 有序数组的平方 - 力扣(LeetCode)

分析:最简单的想法,先对数组内每个元素平法,然后排序,不过这种方法时间复杂度较高

我们可以利用原数组有序的这个特点来寻找简单做法,平方后最大的元素,一定是最小的负数或者是最大的正数,在原数组中一定是在最左边或最右边,所以我们可以利用两个指针来分别指向原数组的头和尾,然后依次向中间靠拢并输出元素的平方,将其放在新数组的最后。有一点点归并排序的味道。

代码实现:

class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        a = [0] * len(nums)
        left, right, key = 0, len(nums) - 1, len(nums) - 1
        while left <= right:
            val1 = nums[left]*nums[left]
            val2 = nums[right]*nums[right]
            if val1 <= val2:
                a[key] = val2
                right -= 1
            else:
                a[key] = val1
                left += 1
            key -= 1
        return a

心得:

最直观的方法往往复杂度较高,要注意用直观方法暴力解题的时候,题目中哪些条件还有用到,这往往是简单解法的关键所在


(4).

209. 长度最小的子数组 - 力扣(LeetCode)

 

分析:此题最直观的解法,先从一个元素开始遍历,然后往后sum,看有多少个才能大于target,然后再从第二个元素数.....很慢,复杂度可以达到O(n²)

双指针法,在简单的解法中,我们是以左边的元素为基准算sum,如果我们用右边的元素作为基准呢?首先我们先从最左边开始,算一个区间和大于target,比如是区间[0, 5],此时,慢指针指向0,快指针指向5,然后我们尝试让sum-0下标的元素,也就是算下[1,5]的和,如果还是大于target,就像1+1+1+1+1+100 > 99,那我们再这样移动慢指针,算[2,5],依次类推,等到小于target了,那我们就移动快指针,再算[low,quick]的区间。这个时间复杂度我也不知道,反正肯定是n到n²之间hhh

代码实现:

class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        low, quick, summ = 0, 0, 0
        lg = len(nums) + 1
        while quick <= len(nums) - 1:
            summ += nums[quick]
            while summ >= target:
                n = quick - low + 1
                lg = min(lg, n)
                summ = summ - nums[low]
                low += 1
            quick += 1
        if lg == len(nums) + 1:
            return 0
        else:
            return lg
                

心得:双指针的应用非常灵活,有时候也很难想,只能多做新题见思路,多复习巩固

相关题目练习(我反正俩都不会,解析都看不懂,摆烂。希望以后的我再回看的时候能看懂吧)

904. 水果成篮 - 力扣(LeetCode)

76. 最小覆盖子串 - 力扣(LeetCode)


(5).

59. 螺旋矩阵 II - 力扣(LeetCode)

 

分析:视频讲解倒是能看懂,但是代码对我自身的水平来说很不好写,特别是对边界条件的判断

总结

数组这章目前感觉很重要的就是

二分法:一定注意题目的有序条件,再有就是对开闭区间与循环条件关系的理解(暂时掌握不好, 我自己一直用的是双闭和left <= right)

双指针:很灵活,可以和上一篇的链表一起感受

总的感觉,虽然数组的结构形式上比链表简单,只有简简单单的数据域,但是感觉题目方面比链表要灵活很多

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值