基于力扣三道题,分析列表上双指针的应用

本篇文章中,我们以力扣的三道题为例,分析双指针的应用。

三道题分别是删除有序数组中的重复项移除元素盛最多水的容器

需要注意这几道题的指针都是针对于链表中的索引。

目录

1、删除有序数组中的重复项

2、  移除元素

3、盛最多水的容器



在前两道题中,两个指针i, j,保持i <= j,

i的作用主要用于指示新的列表中填入元素的相对位置,和有效列表的长度

j的作用则是向后搜索,搜索到符合条件的数值就填入到i所指示的相对位置中。

1、删除有序数组中的重复项

具体来说,在题目删除有序数组中的重复项中,

i,j在移动的过程中,如果发现nums[j] = nums[i],那么j就持续移动,直到找到一个不和nums[i]相等的元素,

此时,让nums[i+1](nums[i]后的一个元素)等于nums[j],此时,让i 自增1,j自增1(开始比较下一个值,使得它不存在重复的元素)

直到j搜索完整个列表。

注意,这道题目的前提是列表必须是有序的,如果是无序的,做法则不成立。

对应代码如下:

class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        lenth = len(nums)
        i, j = 0 , 0
        while(j < lenth):
            if(nums[i] == nums[j]):
                j = j + 1
            else:
                nums[i+1] = nums[j]
                i = i + 1
                j = j + 1
            
        return i+1

2、  移除元素

下面类似地,我们来分析 移除元素

同样是两个指针i, j,保持i <= j

j搜索整个列表,如果和题目要求不能有的数不一样,则在i的位置填入该数,

i每填入一个数,i自增1(i同样用来指示要填入数的位置有效列表的长度

(这道题目不要求列表有序)

对应代码如下:

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

优化:

采用这种做法,容易发现,有可能若i位置的数不是题目数val,也会被改掉 (上述做法一个潜在思想是:用原来列表的空间,重新把所有不是val的数依次排列一遍)

那么有一种想法是,对于i位置不是val的数就不要动,如果等于val,j依次从列表最后开始找,把数填上去,如果填上去的数依然等于val,j再往后找。

过程中要求i < = j 

(这种做法的潜在思想是,把将要构成的有效列表的每一位,都置换成不等于val的数)

对应代码如下:

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        # 对双指针的算法进行优化,
        # 不会改变时间复杂度,但是对原本不是val元素的数值大部分不会更改
        xa = 0
        xb = len(nums) - 1
        while(xa <= xb):
            if(nums[xa] == val):
                nums[xa] = nums[xb]
                xb = xb - 1
            else:                
                xa = xa + 1
        
        return xa

3、盛最多水的容器

对于第三题 盛最多水的容器

或许可以通过搜索的方式在O(n^2)的时间复杂度内,找到所有长度内i,j的组合

但是我们直到,我们以一种更可能的方式搜索,只在O(n)的时间复杂度内解决这道题:

        双指针从列表的两头开始搜索,一定会是一个指针在左,一个指针在右

        由于我们要找出最大的面积,所以两个指针指示的值作比较,较矮的指针优先移动,

        直到两个指针相遇,就一定可以找到最大的面积。

        对应代码如下:

class Solution:
    def maxArea(self, height: List[int]) -> int:
        xa = 0
        xb = len(height)-1

        Smax = 0
        while(xa < xb):
            width = xb - xa
            h = min(height[xa], height[xb])

            Scurr = width * h
            if(Scurr > Smax):
                Smax = Scurr

            if(height[xa] < height[xb]):
                xa = xa + 1
            else:
                xb = xb - 1


        return Smax

所以在上两题中,双指针是必要,第三题双指针降低了时间复杂度。

欢迎交流、指正!

参考题解:

力扣https://leetcode-cn.com/problems/remove-element/solution/yi-chu-yuan-su-by-leetcode-solution-svxi/

力扣https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/solution/力扣https://leetcode-cn.com/problems/container-with-most-water/solution/sheng-zui-duo-shui-de-rong-qi-by-leetcode-solution/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值