python数组总结


二分查找

leetcode 704.二分查找
前提条件: 数组有序,数组中无重复元素
二分区间定义: 左闭右闭 [left, right] or 左闭右开: [left, right)
左闭右闭:while (left <= right), if (nums[middle] > target) right 要赋值为 middle - 1。
如图 target : 11
请添加图片描述

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:
                left = middle + 1
            elif nums[middle] > target:
                right = middle - 1
            else:
                return middle
        return -1

左闭右开:while (left < right), if (nums[middle] > target) right 更新为 middle。
如图 target : 11
请添加图片描述

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

总之right 应该为mid 能到达的值,第一个right也一样。

类似题目
35. 搜索插入位置
假设没有重复
循环之后所有right, mid 在比未找到点小的点上, left在要插入的点上。如下(女友画的 (^ ▽ ^)):
请添加图片描述

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        left, right = 0, len(nums) - 1

        while left <= right:
            middle = (left + right) // 2

            if nums[middle] < target:
                left = middle + 1
            elif nums[middle] > target:
                right = middle - 1
            else:
                return middle
        return right + 1

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

  • 情况一:target 在数组范围的右边或者左边,例如数组{3, 4, 5},target为2或者数组{3, 4, 5},target为6,此时应该返回{-1, -1}
  • 情况二:target 在数组范围中,且数组中不存在target,例如数组{3,6,7},target为5,此时应该返回{-1, -1}
  • 情况三:target 在数组范围中,且数组中存在target,例如数组{3,6,7},target为6,此时应该返回{1, 1}
class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        def getRightBorder(nums:List[int], target:int) -> int:
            left, right = 0, len(nums)-1
            rightBoder = -2 # 记录一下rightBorder没有被赋值的情况
            while left <= right:
                middle = left + (right-left) // 2
                if nums[middle] > target:
                    right = middle - 1
                else: # 找到最右边的为target的坐标,但是会向右超出一个
                    left = middle + 1
                    rightBoder = left
    
            return rightBoder  # 多加了 1
        
        def getLeftBorder(nums:List[int], target:int) -> int:
            left, right = 0, len(nums)-1 
            leftBoder = -2 # 记录一下leftBorder没有被赋值的情况
            while left <= right:
                middle = left + (right-left) // 2
                if nums[middle] >= target: #  找到最左边的target,但是会多往左边一个
                    right = middle - 1;
                    leftBoder = right;
                else:
                    left = middle + 1
            return leftBoder  # 多减了 1
        leftBoder = getLeftBorder(nums, target)
        rightBoder = getRightBorder(nums, target)
        # 情况一
        if leftBoder == -2 or rightBoder == -2: return [-1, -1]
        # 情况三
        if rightBoder -leftBoder >1: return [leftBoder + 1, rightBoder - 1]
        # 情况二
        return [-1, -1]

69. x的平方根

class Solution:
    def mySqrt(self, x: int) -> int:
        low, high, ans = 0, x, -1
        while low <= high:
            mid = (low + high) // 2
            if mid * mid <= x:
                ans = mid
                low = mid + 1
            else:
                high = mid - 1
        return ans

367. 有效的完全平方数

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

移除元素

用双指针法:让a表示一个index, 让b表示第一个index,让a一直往后移动,遍历整个数组,当且仅当我们发现 nums[a] != val 的时候,我们把这个数拷贝到 b 指向的位置,默认 b 是从 0 开始的,然后 b += 1 指向下一个位置。

27. 移除元素

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

26. 删除有序数组中的重复项
这里要注意 a + 1 的顺序,不能放到最后

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

283. 移动零
b最后在第一个0上,a溢出了一位,所以最后a和b的距离刚好就是0的个数。

class Solution:
    def moveZeroes(self, nums: List[int]) -> None:
        a, b = 0, 0
        while a <= len(nums) - 1:
            if nums[a] != 0:
                nums[b] = nums[a]
                b += 1
            a += 1
        nums[b:] = [0 for _ in range(a - b)]

844. 比较退格的字符串
这里存在多 ‘ # ’ 的情况,如果没有字符可以退了,就让b留在-1的点上。

    def backspaceCompare(self, s, t):
        def printStr(strs):
            a, b = 0, 0
            str_li = list(strs)
            while a < len(str_li):
                str_li[b] = str_li[a]
                if str_li[a] == '#':
                    b -= 2
                    if b <= -1:
                        b = -1
                a += 1
                b += 1
            return str_li[:b]
        str_1 = printStr(s)
        str_2 = printStr(t)
        if str_1 == str_2:
            return True
        else:
            return False

有序数组的平方

class Solution:
    def sortedSquares(self, nums):
        i, j, k = 0, len(nums) - 1, len(nums) - 1
        res = [0 for i in range(len(nums))]
        while i <= j:
            if nums[i] ** 2 > nums[j] ** 2:
                res[k] = nums[i] ** 2
                i += 1
                k -= 1
            else:
                res[k] = nums[j] ** 2
                j -= 1
                k -= 1
        return res

长度最小的子数组

使用滑动窗口:窗口即满足其和长度 >= s 的长度的连续子数组。
这里是 num_sum >= target 而不是 num_sum > target 不加=会错过最小窗口

class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        length = float('inf')
        num_sum = 0
        left = 0
        for right in range(len(nums)):
            num_sum += nums[right]
            while num_sum >= target:
                length = min(length, right - left + 1)
                num_sum -= nums[left]
                left += 1
       return 0 if length == float('inf') else length

904.水果成篮
这里的counter是一个字典

class Solution:
    def totalFruit(self, fruits: List[int]) -> int:
        left, length = 0, 0
        counter = collections.Counter()
        for j, typ in enumerate(fruits):
            counter[typ] += 1
            while len(counter) > 2:
                counter[fruits[left]] -= 1
                if counter[fruits[left]] == 0:
                    del counter[fruits[left]]
                left += 1
            length = max(length, j - left + 1)
        return length

76. 最小覆盖子串
核心思想:滑动窗口

  1. 首先创建一个初始数量都为0的空字典,然后将t中每种元素需要的数量写入,并用count记录 t 的总元素个数
  2. 遍历s,每过一个元素,字典中的元素减1,一旦遇见t中的元素,字典中该元素减1,count减一
  3. 当count等于0,left找到s中第一个存在于t的元素,计算left和right的距离
  4. left离开当前元素(该元素存在于t中),count加一,字典中该元素加一,right向右寻找该元素(其中当窗口中含有某种元素多于t所需时,该元素在字典中会变为负数,left向左寻找下一个t中元素时可以跳过该元素,但是当窗口划出该元素需要将该元素在字典中重新加上)
class Solution:
    def minWindow_1(self, s, t):
        left = 0
        length = len(s) + 1
        dict_t = collections.defaultdict(int)
        for val in t:
            dict_t[val] += 1
        count = len(t)
        for right, val in enumerate(s):
            if dict_t[val] > 0:
                count -= 1
            dict_t[val] -= 1  # 如果有多余的t需要的元素,该元素会变成负的,在寻找下一个left的时候可以直接跳过
            if count == 0:
                while True:
                    if dict_t[s[left]] == 0:
                        break
                    dict_t[s[left]] += 1  # left 在左移的过程中需要将移出去的t需要的元素重新加上
                    left += 1
                if length > right - left + 1:
                    length = right - left + 1
                    min_l = left
                    min_r = right + 1
                dict_t[s[left]] += 1
                count += 1
                left += 1
        return '' if length == len(s) + 1 else s[min_l: min_r]

螺旋矩阵

坚持每条边左闭右开

  • 填充上行从左到右
  • 填充右列从上到下
  • 填充下行从右到左
  • 填充左列从下到上
class Solution:
    def generateMatrix(self, n: int) -> List[List[int]]:
        matrix = [[0] * n for _ in range(n)]
        left, right, up, down = 0, n - 1, 0, n - 1
        number = 1  # 要填充的数字
        while left < right and up < down:
            # 从左至右填充
            for i in range(left, right):
                matrix[up][i] = number
                number += 1
            # 从上至下填充
            for j in range(up, down):
                matrix[j][right] = number
                number += 1
            # 从右至左填充
            for i in range(right, left, -1):
                matrix[down][i] = number
                number += 1
            # 从下至上填充
            for j in range(down, up, -1):
                matrix[j][left] = number
                number += 1
            left += 1
            right -= 1
            up += 1
            down -= 1
        # 如果为基数,填充中间,序号从零开始
        if n % 2:
            matrix[n // 2][n // 2] = number
        return matrix 

感谢阅读

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值