代码随想录|Day1|数组 part01

1、数组理论基础(了解一下数组基础,以及数组的内存空间地址

文章链接:代码随想录

 * (关注)二维数组在内存的空间地址是连续的么?

 2、704.二分查找

 思路:这是给出一个数组(无重复),然后根据输入的数值找到对应的下标。

 首先:简单的暴力遍历:(执行用时: 44 ms)

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        a = 0
        # print(nums)
        for i in nums:
            if int(target) == int(i):
                print(a)
                return a
            else:
                a = a + 1
        if a >= len(nums):
            # print("-1")
            return -1
    
    

 或者更直接的:(执行用时: 56 ms)

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        if target in nums :
            return nums.index(target)
        else:
            return -1

今日主角:二分法

 二分法第一种写法:左闭右闭即[left, right]   (执行用时: 44 ms)

  • 时间复杂度:O(log n)
  • 空间复杂度:O(1)

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        left = 0
        right = len(nums) - 1
        while left <= right:  # 当left==right,区间[left, right]依然有效,所以用 <=
            middle = left + (right-left) // 2  
            # 不直接用(Left+right)//2 是因为当left和right都很大的时候,(left + right)可能会导致整数溢出。而使用left + (right - left) // 2的方式可以避免这个问题,因为right - left保证了相减操作不会超出整数的表示范围。
            if nums[middle] > target:
                right = middle-1   ## target在左区间,所以[left, middle - 1]
            elif nums[middle] < target:
                left = middle+1   # target在右区间,所以[middle + 1, right]
            else:
                return middle   # 数组中找到目标值,直接返回下标
        return -1    # 未找到目标值

二分法第二种写法:左闭右开即[left, right) (执行用时: 40 ms)

  • 时间复杂度:O(log n)
  • 空间复杂度:O(1)

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        left = 0
        right = len(nums) # 定义target在左闭右开的区间里,即:[left, right)
        while left < right:# 因为left == right的时候,在[left, right)是无效的空间,所以使用 <
            middle = left + (right-left) // 2  
            # 不直接用(Left+right)//2 是因为当left和right都很大的时候,(left + right)可能会导致整数溢出。而使用left + (right - left) // 2的方式可以避免这个问题,因为right - left保证了相减操作不会超出整数的表示范围。
            if nums[middle] > target:
                right = middle # target 在左区间,在[left, middle)中
            elif nums[middle] < target:
                left = middle+1  # target 在右区间,在[middle + 1, right)中
            else:
                return middle  # 数组中找到目标值,直接返回下标
        return -1  # 未找到目标值

 3、34.二分查找拓展

题目链接:力扣

文章讲解:代码随想录

首先,简单的暴力遍历:(执行用时: 64 ms)

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        all = []
        for i in range(0,len(nums)):
            if nums[i] == target:
                all.append(i)
        if len(all)==0:
            return[-1,-1]
        else:
            return [all[0],all[-1]]

接着,二分法:(用左闭右闭即[left, right] )

# 1、首先,在 nums 数组中二分查找 target;
# 2、如果二分查找失败,则 binarySearch 返回 -1,表明 nums 中没有 target。此时,searchRange 直接返回 {-1, -1};
# 3、如果二分查找成功,则 binarySearch 返回 nums 中值为 target 的一个下标。然后,通过左右滑动指针,来找到符合题意的区间
class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        def binarySearch(nums:List[int], target:int) -> int:
            left, right = 0, len(nums)-1
            while left<=right: # 不变量:左闭右闭区间
                middle = left + (right-left) // 2
                if nums[middle] > target:
                    right = middle - 1
                elif nums[middle] < target: 
                    left = middle + 1
                else:
                    return middle
            return -1
        index = binarySearch(nums, target)
        if index == -1:return [-1, -1] # nums 中不存在 target,直接返回 {-1, -1}
        # nums 中存在 targe,则左右滑动指针,来找到符合题意的区间
        left, right = index, index
        # 向左滑动,找左边界
        while left -1 >=0 and nums[left - 1] == target: left -=1
        # 向右滑动,找右边界
        while right+1 < len(nums) and nums[right + 1] == target: right +=1
        return [left, right]
# 1、首先,在 nums 数组中二分查找得到第一个大于等于 target的下标(左边界)与第一个大于target的下标(右边界);
# 2、如果左边界<= 右边界,则返回 [左边界, 右边界]。否则返回[-1, -1]
class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        def binarySearch(nums:List[int], target:int, lower:bool) -> int:
            left, right = 0, len(nums)-1
            ans = len(nums)
            while left<=right: # 不变量:左闭右闭区间
                middle = left + (right-left) //2 
                # lower为True,执行前半部分,找到第一个大于等于 target的下标 ,否则找到第一个大于target的下标
                if nums[middle] > target or (lower and nums[middle] >= target): 
                    right = middle - 1
                    ans = middle
                else: 
                    left = middle + 1
            return ans

        leftBorder = binarySearch(nums, target, True) # 搜索左边界
        rightBorder = binarySearch(nums, target, False) -1  # 搜索右边界
        if leftBorder<= rightBorder and rightBorder< len(nums) and nums[leftBorder] == target and  nums[rightBorder] == target:
            return [leftBorder, rightBorder]
        return [-1, -1]

# 1、首先,在 nums 数组中二分查找得到第一个大于等于 target的下标leftBorder;
# 2、在 nums 数组中二分查找得到第一个大于等于 target+1的下标, 减1则得到rightBorder;
# 3、如果开始位置在数组的右边或者不存在target,则返回[-1, -1] 。否则返回[leftBorder, rightBorder]
class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        def binarySearch(nums:List[int], target:int) -> int:
            left, right = 0, len(nums)-1
            while left<=right: # 不变量:左闭右闭区间
                middle = left + (right-left) //2 
                if nums[middle] >= target: 
                    right = middle - 1
                else: 
                    left = middle + 1
            return left  # 若存在target,则返回第一个等于target的值 

        leftBorder = binarySearch(nums, target) # 搜索左边界
        rightBorder = binarySearch(nums, target+1) -1  # 搜索右边界
        if leftBorder == len(nums) or nums[leftBorder]!= target: # 情况一和情况二
            return [-1, -1]
        return [leftBorder, rightBorder]

4、35.二分查找拓展(搜索插入位置)

题目链接:力扣

文章讲解:代码随想录

首先,简单的暴力遍历:(执行用时: 52 ms)

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        for i in range(0,len(nums)):
            if nums[i] >= target:
                return i   #一旦发现大于或者等于target的num[i],那么i就是我们要的结果
    #目标值在数组所有元素之后的情况    
    return len(nums)   #// 如果target是最大的,或者 nums为空,则返回nums的长度
    

二分法:(执行用时: 60 ms)

 思路:是先判断目标值是否大于列表中所有的值,若大于,则返回列表长度;若不大于,则找出第一个大于等于目标值的下标,若目标值在列表中,则找到了该下表标,若目标值不在列表中,则加入该目标值,返回其下标。

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        # for i in range(0,len(nums)):
        #     if nums[i] == target:
        #         return i
        def erfenfa(nums: List[int], target: int):
            left = 0
            right = len(nums)-1
            while left <= right: 
                middle = left + (right-left)//2

                if nums[middle] >= target:
                    right = middle -1 
                else:
                    left = middle +1
            return left
        if target > nums[-1]:
            return len(nums)
        else:
            left1 = erfenfa(nums,target)
            if nums[left1] == target:
                return  left1
            else:
                # print(left1)
                return left1

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
           #  // 分别处理如下四种情况
       # // 目标值在数组所有元素之前 [0,0)
      #  // 目标值等于数组中某一个元素 return middle
       # // 目标值插入数组中的位置 [left, right) ,return right 即可
     #   // 目标值在数组所有元素之后的情况 [left, right),因为是右开区间,所以 return right
        return right + 1

 5、27.移除元素

  首先:简单的暴力遍历:

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        i, l = 0, len(nums)
        while i < l:
            if nums[i] == val: # 找到等于目标值的节点
                for j in range(i+1, l): # 移除该元素,并将后面元素向前平移
                    nums[j - 1] = nums[j]
                l -= 1
                i -= 1
            i += 1
        return l

双指针:

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
# 快慢指针
        fast = 0  # 快指针
        slow = 0  # 慢指针
        size = len(nums)
        while fast < size:  # 不加等于是因为,a = size 时,nums[a] 会越界
            # slow 用来收集不等于 val 的值,如果 fast 对应值不等于 val,则把它与 slow 替换
            if nums[fast] != val:
                nums[slow] = nums[fast]
                slow += 1
            fast += 1
        return slow
            

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
# 快慢指针
        fast = 0  # 快指针
        slow = 0  # 慢指针
        size = len(nums)
        for fast in range(0,size):  # 不加等于是因为,a = size 时,nums[a] 会越界
            # slow 用来收集不等于 val 的值,如果 fast 对应值不等于 val,则把它与 slow 替换
            if nums[fast] != val:
                nums[slow] = nums[fast]
                slow += 1
            # fast += 1
        return slow

 6、26.删除有序数组的重复项

题目链接:力扣

  首先:简单的暴力遍历:

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

  双指针:

class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        fast = 1
        slow = 0
        for fast in range(1,len(nums)):
            if nums[slow]!=nums[fast]:
                nums[slow+1] = nums[fast]
                slow = slow+1
            else:
                slow=slow
        return slow +1

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值