二、数组及LeetCode典型题目分析

一、线性表、数组基础

很多问题就是在一个数组中解决的
栈、队列、堆的底层都是基于数组,封装的数据结构,后面我们会遇到很灵活的算法问题。本质就是在数组里面做操作。
下面我们来讲一个简单算法,二分查找法:

class Solution(object):
    def BinarySearch(self, arr, target):
        # [l, r]的区间采用二分查找法
        l, r = 0, len(arr) -1
        while l <= r:
            mid = l+(r-l)//2
            if target == arr[mid]:
                return mid
            elif target > arr[mid]:
                l = mid +1
            else:
                r = mid -1
        return -1    

由于我们选用了[l, r]这个区间,那么进行循环的时候,控制条件l是可以和r相等的,当target<arr[mid]的时候,说明目标在区间的左边,r就应该等于mid-1(因为是开区间,所以是mid-1),同理我们可以知道l的取值就是mid+1了。
mid = l+(r-l)//2的写法是为了防止数值的溢出,要是写成(l+r)//2的形式,那么当r和l都非常的大的时候,就可能出现数值溢出的问题。
时间复杂度:O(logn)
空间复杂度:O(1)

二、一些思路及LeetCode代表题

1、移除元素

LeetCode 283题:移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
示例:
输入: [0,1,0,3,12]
输出: [1,3,12,0,0]
说明:
必须在原数组上操作,不能拷贝额外的数组。
尽量减少操作次数。

思路一:三个for循环解决问题。用一个格外的数组来存取nums中的非0元素,然后一一赋值到nums中,nums剩下的位置全部赋予0就行了。
时间复杂度:O(n)
空间复杂度:O(n)

class Solution:
    def moveZeroes(self, nums):
        """
        :type nums: List[int]
        :rtype: void Do not return anything, modify nums in-place instead.
        """
        nonZeros= []
        for i in nums:
            if i:
                nonZeros.append(i)
        for i in range(len(nonZeros)):
            nums[i] = nonZeros[i]
        
        for i in range(len(nonZeros),len(nums)):
            nums[i]=0          

这种思路的话,多用了一个数组,带来了空间复杂度O(n),下面我们就针对这一点进行一个优化。
思路二:采用快慢指针的思想,用慢指针k来指向非零元素,用快指针来遍历该数组。循环完成之后,那么[0,...,k)中都是非0元素。我们后面需要做的就是将后面的元素赋值为0,这样就完成了这个思路
时间复杂度:O(n)
空间复杂度:O(1)

class Solution:
    def moveZeroes(self, nums):
        """
        :type nums: List[int]
        :rtype: void Do not return anything, modify nums in-place instead.
        """
        k = 0
        for index,item in enumerate(nums):
            if item:
                nums[k]=item
                k+=1
        for i in range(k, len(nums)):
            nums[i]=0

想到这里来了之后,我们就会思考,还能不能将这个算法变得更好呢?答案是yes。
思路三:我们还是采用了快慢指针的操作,然后将非0元素和0元素进行一个互换,这样的话,就一个for循环就完成了整个操作。[0,...,k)中都是非0元素, [k,...,len(nums)]就是0元素了。
时间复杂度:O(n)
空间复杂度:O(1)

class Solution:
    def moveZeroes(self, nums):
        """
        :type nums: List[int]
        :rtype: void Do not return anything, modify nums in-place instead.
        """
        k = 0
        for index, item in enumerate(nums):
            if item:
                nums[k], nums[index] = nums[index],nums[k]
                k+=1     

到了这里之后,我们还能不能够进行进一步的优化呢?答案是yes。因为很多时候,我们的优化都是针对的特殊情况。

class Solution:
    def moveZeroes(self, nums):
        """
        :type nums: List[int]
        :rtype: void Do not return anything, modify nums in-place instead.
        """
        k = 0
        for index, item in enumerate(nums):
            if item:
                if index!=k:
                    nums[k], nums[index] = nums[index],nums[k]
                    k+=1
                else:
                    k+=1    

下面还有一些类似于改思想的题目:
LeetCode 26, 27, 80
小伙伴们可以自己去尝试一下

2、对撞指针法

LeetCode 167 两数之和 II - 输入有序数组
给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。
函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。
说明:
返回的下标值(index1 和 index2)不是从零开始的。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
示例:
输入: numbers = [2, 7, 11, 15], target = 9
输出: [1,2]
解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。
思路一:暴力解法,进行双层的遍历,然后时间复杂度是O(n^2),遍历i,j,检测i和j所对应的是不是target。要是一时没有想法,就能给出结果,这仍然是一个可行的解决,解决完,提交的话,LeetCode会告诉大家,这是会超时的。数据的规模为10000,运行起来就显得比较慢了,数据规模要是100000,就不能在我们容仍的时间内完成这个问题。因此我们必须要有更高效的解法。
时间复杂度:O(n^2)
空间复杂度:O(1)
思路二:采用二分搜索法,第一层循环进行数组的遍历,针对每个元素,找剩下部分找target-element是不是存在,存在返回就行了。然后试了一下,是accept的。因为前面讲了二分查找法,大家思考一下,这个方法还是挺简单的。
时间复杂度:O(nlogn)
空间复杂度:O(1)

class Solution:
    def twoSum(self, numbers, target):
        """
        :type numbers: List[int]
        :type target: int
        :rtype: List[int]
        """
        n = len(numbers)
        for index, item in enumerate(numbers):
            if index<n-1:
                l, r = index+1, n-1
                while l<=r:
                    mid = l+(r-l)//2
                    if numbers[mid]==target-item:
                        return [index+1, mid+1]
                    elif numbers[mid]>target-item:
                        r=mid-1
                    else:
                        l=mid+1
        return None        

到这里之后,我们想一想还有没有更加高效的方法来解决这个问题呢?答案是yes的。下面就是用对撞指针的方式来解决这个问题
思路三:因为我们的数组是排序过的,然后左边的小,右边的大,左边的开始记为i,右边的开始记为j,然后看nums[i]和nums[j]的大小,要是他们相等,那么正好i和j就是我们想找的,要是nums[i]+nums[j]<target,那么就说明了nums[i]是小了,那么i就需要向前进,要是nums[i]+nums[j]>target了,就说了nums[j]大了,那么j就需要向前面走了。知道了这个思路之后,我们下面就来进行一个实现:
时间复杂度:O(n)
空间复杂度:O(1)

class Solution(object):
    def twoSum(self, numbers, target):
        """
        :type numbers: List[int]
        :type target: int
        :rtype: List[int]
        """
        l, r = 0, len(numbers)-1
        
        while l<r:
            if numbers[l] + numbers[r]==target:
                return [l+1, r+1]
            elif numbers[l] + numbers[r]<target:
                l+=1
            else:
                r-=1

采用了对撞指针的题目还有:
Leetcode 11, 125, 344, 345
大家可以去尝试一下这些简单、中等的题目哈

3、滑动窗口法

Leetcode 209:长度最小的子数组
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组。如果不存在符合条件的连续子数组,返回 0。
示例:
输入: s = 7, nums = [2,3,1,2,4,3]
输出: 2
解释: 子数组 [4,3] 是该条件下的长度最小的连续子数组。
进阶:
如果你已经完成了O(n) 时间复杂度的解法, 请尝试 O(n log n) 时间复杂度的解法。
思路一:第一种思路就是暴力法,采用三次循环来达到目的,这样的解决方法的时间复杂度是就是O(n3),可以将这种方法优化到O(n2)去。
思路二:采用滑动窗口法,
时间复杂度:O(n)
空间复杂度:O(1)

class Solution:
    def minSubArrayLen(self, s, nums):
        """
        :type s: int
        :type nums: List[int]
        :rtype: int
        """
        sum = 0
        l,r=0,-1
        res=len(nums)+1
        
        while l<len(nums):
            if r+1<len(nums) and sum<s:
                r+=1
                sum+=nums[r]
            else:
                sum-=nums[l]
                l+=1
            if sum>=s:
                res = min(res, r-l+1)

        if res==len(nums)+1:
            return 0;

        return res

欢迎各位小伙伴批评指正哈。
类似的题目如下:
Leetcode 3, 76, 438

持续更新中...
数据结构与算法系列博客:
一、数据结构与算法概述
二、数组及LeetCode典型题目分析
三、链表(Linked list)以及LeetCode题
四、栈与队列(Stack and Queue
五、树(Trees)
六、递归与回溯算法
七、动态规划
八、排序与搜索
九、哈希表
参考资料:
1、https://coding.imooc.com/class/82.html
2、https://leetcode-cn.com/problemset/all/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容

  • <center>#1 Two Sum</center> link Description:Given an arr...
    铛铛铛clark阅读 2,137评论 0 3
  • <center>#104 Maximum Depth of Binary Tree</center> link D...
    铛铛铛clark阅读 1,568评论 0 0
  • 本文内容为练习LeetCode题目时的解题思路和不同算法的记录,实现语言为C++,代码保存在Github,均已在L...
    SK木眠阅读 984评论 0 0
  • LeetCode 刷题随手记 - 第一部分 前 256 题(非会员),仅算法题,的吐槽 https://leetc...
    蕾娜漢默阅读 17,685评论 2 36
  • Ansel Adams说:我们带到摄影中去的是所有我们读过的书,看过的电影,听过的音乐,爱过的人。
    Abby王阅读 192评论 0 2