算法通关村——双指针的妙用

白银挑战——双指针思想以及应用

1.双指针思想

所谓双指针其实是两个变量,不一定是真正的指针

2.删除元素专题

2.1原地移除所有数值等于val的元素

leetcode27.给你一个数组Nums和一个值val,你需要原地移除所有数值等于val的元素,并返回移除后数组的新长度。要求:不要使用额外的数组空间,你必须仅使用O(1)额外空间并原地修改输入数组。元素的舒徐可以改变。你不需要考虑数组中超出新长度后面的元素。

第一种:快慢双指针

第二种:对撞型双指针

拓展:对撞双指针+覆盖

class RemoveElement:
    # 第一种:快慢双指针
    def removeElement(self, nums, val):
        fast = 0
        slow = 0
        while fast < len(nums):
            if nums[fast] != val:
                nums[slow] = nums[fast]
                slow += 1
            fast += 1
        return slow

    # 第二种:对撞型双指针
    def removeElement2(self, nums, val):
        left = 0
        right = len(nums) - 1
        while left <= right:
            if nums[left] == val and nums[right] != val:
                tmp = nums[right]
                nums[right] = nums[left]
                nums[left] = tmp
            if nums[left] != val:
                left += 1
            if nums[right] == val:
                right -= 1
        return left

    # 对撞双指针+覆盖
    def removeElement3(self, nums, val):
        left = 0
        right = len(nums) - 1
        while left <= right:
            if nums[left] == val:  # 注意这里没有nums[right] != val,为什么?
                nums[left] = nums[right]
                right -= 1
            else:
                left += 1
        return left


if __name__ == '__main__':
    nums = [0, 1, 2, 2, 3, 0, 4, 2]
    nums2 = [3,2,2,3]
    val = 2
    val2 = 3
    removeElement = RemoveElement()
    print(removeElement.removeElement3(nums, val))
    print(nums)

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

LeetCode26:给你一个有序数组nums,请你原地删除重复出现的元素,使每个元素只出现一次,返回删除后数组的新长度。不要额外的数组空间,你必须在原地修改输入数组,并在使用O(1)额外空间的条件下完成。

class RemoveDuplicates:
    def remove_duplicates(self, nums):
        slow = 1
        for i in range(1, len(nums)):
            if nums[i] != nums[slow - 1]:
                nums[slow] = nums[i]
                slow += 1
        return slow


if __name__ == '__main__':
    nums = [0, 0, 1, 1, 1, 2, 2, 3, 3, 4]
    removeDuplicates = RemoveDuplicates()
    print(removeDuplicates.remove_duplicates(nums))
    print(nums)

3.元素奇偶移动专题

LeetCode905:按奇偶排序数组。给定一个非负整数数组A,返回一个数组,在该数组中,A的所有偶数元素之后跟着所有奇数元素。你可以返回满足此条件的任何数组作为答案。

采用对撞型指针。

class SortArrayByParity:
    def sortArrayByParity(self, nums):
        n = len(nums)
        res = [0] * n
        left = 0
        right = n - 1
        for num in nums:   
            if num % 2 == 0:
                res[left] = num
                left += 1
            else:
                res[right] = num
                right -= 1
        return res


if __name__ == '__main__':
    nums = [3, 1, 2, 4]
    sort_array = SortArrayByParity()
    print(sort_array.sortArrayByParity(nums))

4.数组轮转问题

LeetCode189:给你一个数组,将数组中的元素向右轮转K个位置,其中K是非负数。

方法:两轮翻转

class Rotate:
    def rotate(self, nums, k):
        length = len(nums)
        k %= length
        nums[:] = nums[::-1]
        nums[:k] = nums[:k][::-1]
        nums[k:] = nums[k:][::-1]

if __name__ == '__main__':
    nums = [1, 2, 3, 4, 5, 6, 7]
    rotater = Rotate()
    rotater.rotate(nums, 3)
    print(nums)

[m : ] 代表列表中的第m+1项到最后一项

[ : n] 代表列表中的第一项到第n项

a=[1,2,3.4,5]
print(a)
[ 1 2 3 4 5 ]

print(a[-1]) 取最后一个元素
结果:[5]

print(a[:-1]) 除了最后一个取全部
结果:[ 1 2 3 4 ]

print(a[::-1]) 取从后向前(相反)的元素
结果:[ 5 4 3 2 1 ]

print(a[2::-1]) 取从下标为2的元素翻转读取
结果:[ 3 2 1 ]

print(a[1:]) 取第二个到最后一个元素
结果:[2 3 4 5]

5.数组的区间专题

LeetCode228:给定一个无重复元素的有序整数数组nums。返回恰好覆盖数组中所有数字的最小有序区间范围列表。也就是说,nums的每个元素都恰好被某个区间范围所覆盖,并且不存在属于某个范围但不属于nums的数组x。列表中的每个区间范围[a,b]应该按如下格式输出:"a->b"

方法:快慢指针:慢指针指向每个区间的起始位置,快指针从慢指针位置快事向后遍历直到不满足连续递增(或快指针达到数组边界),则当前区间结束

实现的精华是:fast+1 == nums.length || nums[fast] + 1 != nums[fast+1]

class SummaryRanges:
    def summaryRanges(self, nums):
        n = len(nums)
        slow,fast = 0, 0
        res = []
        while fast < n:
            if fast < n - 1 and nums[fast] + 1 == nums[fast + 1]:
                fast = fast + 1
            else:
                res.append((nums[slow], nums[fast]))
                slow = fast + 1
                fast = fast + 1
        print(res)
        # 转换成需要的字符串样式
        def p(x):
            slow, fast = x
            if slow == fast:
                return str(slow)
            else:
                return str(slow) + "->" + str(fast)
        return list(map(p, res))


if __name__ == '__main__':
    nums = [0, 2, 3, 4, 6, 8, 9]
    summaryRanges = SummaryRanges()
    print(summaryRanges.summaryRanges(nums))

map() 会根据提供的函数对指定序列做映射。

第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表.

6.字符串替换空格问题

请实现一个函数,将一个字符串中的每个空格替换成"%20"

class ReplaceSpace:
    # 如果长度不可变,我们需要申请一个更大的空间
    def replaceSpace(self, s):
        res = []
        for c in s:
            if c == ' ':
                res.append("%20")
            else:
                res.append(c)
        return "".join(res)

    # 如果使用长度可变的空间来管理原始数组,或者原始数组申请的足够大,
    # 这时候就可能要求你不能申请O(n)大小的空间
    # 方法:先遍历一遍字符串,可以统计出字符串中的空格个数
    # 接下来从字符串的尾部开始替换和复制
    def replaceSpace2(self, s):
        counter = s.count(' ')
        res = list(s)
        res.extend([' '] * counter * 2)
        left, right = len(s) - 1, len(res) - 1
        while left >= 0:
            if res[left] != ' ':
                res[right] = res[left]
                right -= 1
            else:
                res[right - 2: right + 1] = "%20"
                right -= 3
            left -= 1
        return ''.join(res)

if __name__ == '__main__':
    replaceSpace = ReplaceSpace()
    s = "hello python!"
    print(replaceSpace.replaceSpace2(s))

Python中的 .join() 函数

这个函数展开来写应该是str.join(item),join函数是一个字符串操作函数

str表示字符串(字符),item表示一个成员,注意括号里必须只能有一个成员,比如','.join('a','b')这种写法是行不通的

','.join('abc') 代码的含义是“将字符串abc中的每个成员以字符''分隔开再拼接成一个字符串”,输出结果为:'a,b,c'

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值