代码随想录算法训练营第一天(py) | 704. 二分查找、27. 移除元素

数组是存放在连续内存空间上的相同类型数据集合。
数组元素不能删除只能覆盖。

704.二分查找(easy)

力扣链接
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

思路1:暴力遍历

从头到尾遍历一遍,如果找到则返回下标。循环结束还没找到则返回-1

class Solution(object):
    def search(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        for i in range(len(nums)):
            if(nums[i]==target):
                return i
        return -1

执行用时:31ms 消耗内存:12.2MB

思路2:二分查找

1.左闭右开写法

由于升序排列,且无重复元素,因此可以用二分查找

  1. 定义一个左闭右开区间(闭区间也可以,但是程序写法会有不同),并找到中间位置元素。
  2. 将中间位置元素与目标比较,可以判断目标在左边还是右边区间,再根据左右判断结果缩小区间。注意:区间缩小时的开闭也要与刚开始定义时一样。
  3. 循环比较与缩小区间,到最后会两边逼近目标值,此时left=right,返回结果。
class Solution(object):
    def search(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        left = 0
        right = len(nums)  # 左闭右开区间[left,right)
        while(left<right): # 因为left == right的时候,在[left, right)是无效的空间,所以使用 <
            mid = (left + right)/2
            if(target > nums[mid]): # 如果target在右半区间,则在右边继续查找
                left = mid + 1
            elif(target < nums[mid]): # 如果target在左半区间,则在左边继续查找
                right = mid  # 右边是开区间,所以不-1
            else:  # 如果正好在中间
                return mid
        return -1 # 如果循环结束还没找到就返回-1

2.左闭右闭写法

与左闭右开相似,有以下2处不同:

  1. right = len - 1;因为nums[len]取不到,想要闭区间就要len-1
  2. right = mid - 1;闭区间,所以也-1
class Solution(object):
    def search(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        left = 0
        right = len(nums)-1  # 左闭右闭区间[left,right]
        while(left<=right): # 因为left == right的时候,在[left, right]依然有效,因此<=
            mid = (left + right)/2
            if(target > nums[mid]): # 如果target在右半区间,则在右边继续查找
                left = mid + 1
            elif(target < nums[mid]): # 如果target在左半区间,则在左边继续查找
                right = mid - 1  # 右边也是闭区间,所以-1
            else:  # 如果正好在中间
                return mid
        return -1 # 如果循环结束还没找到就返回-1

27.移除元素(easy)

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

示例 1: 给定 nums = [3,2,2,3], val = 3, 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 你不需要考虑数组中超出新长度后面的元素。
示例 2: 给定 nums = [0,1,2,2,3,0,4,2], val = 2, 函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。

你不需要考虑数组中超出新长度后面的元素。

思路1:暴力解法

由于数组是在连续空间内存储,因此不能直接对中间的元素进行删除。
暴力解法的思路为,两层for循环,外层寻找目标,内层调整数组。具体过程如下:

  1. 外层循环对数组遍历。如果找到等于val的元素,则进入内层循环。
  2. 内层循环对val及后面的元素进行处理。将后面的元素逐个前移,覆盖val元素。
class Solution(object):
    def removeElement(self, nums, val):
        """
        :type nums: List[int]
        :type val: int
        :rtype: int
        """
        i = 0
        while(i<len(nums)):
            if(nums[i]==val):
                for j in range(i+1, len(nums)):
                    nums[j-1] = nums[j]
                nums.pop()

            else:
                i += 1  # 当不相等时外循环指针才继续向前,这是为了防止漏判

思路2:快慢指针

通过一个快指针和慢指针,在同一个循环内完成查找和前移元素的工作。
快指针:找到不含val的元素
慢指针:负责“维护新数组”
形象的比喻:
想象有一排椅子,这些椅子上坐着不同颜色的帽子的人,现在你的任务是要移除所有带红帽子的人。你可以使用两个标志(或者说是指针)来帮助你完成这个任务:

慢指针(slow):这个指针指向最终留下的人群中的最后一个位置。初始时,它指向第一个位置。
快指针(fast):这个指针用来遍历所有的椅子,寻找不带红帽子的人。
开始时,快指针从第一个椅子开始移动:

每当快指针指向一个不带红帽子的人时,你就让这个人坐到慢指针所在的位置,并且将慢指针向前移动一个位置。这样做的目的是把所有不需要移除的人都集中到队列的前端。
如果快指针指向的是带红帽子的人,就让快指针继续前进,寻找下一个不带红帽子的人。
当快指针遍历完所有的椅子后,慢指针前面的所有位置都是不带红帽子的人,而慢指针后面的所有位置都是空出来的或者不需要关心的位置。这样,你就成功地移除了所有带红帽子的人,并且保持了其他人的顺序不变。

class Solution(object):
    def removeElement(self, nums, val):
        """
        :type nums: List[int]
        :type val: int
        :rtype: int
        """

        slow_index = 0
        fast_index = 0
        while fast_index < len(nums):
            if(nums[fast_index] != val): # 如果没找到要删除的
                nums[slow_index]=nums[fast_index] # 让元素前移
                slow_index += 1 # 则慢指针和快指针同步+1
            fast_index += 1
        # nums = nums[0:slow_index]
        print(nums)
        return slow_index
  • 24
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第二十二天的算法训练营主要涵盖了Leetcode题目中的三道题目,分别是Leetcode 28 "Find the Index of the First Occurrence in a String",Leetcode 977 "有序数组的平方",和Leetcode 209 "长度最小的子数组"。 首先是Leetcode 28题,题目要求在给定的字符串中找到第一个出现的字符的索引。思路是使用双指针来遍历字符串,一个指向字符串的开头,另一个指向字符串的结尾。通过比较两个指针所指向的字符是否相等来判断是否找到了第一个出现的字符。具体实现的代码如下: ```python def findIndex(self, s: str) -> int: left = 0 right = len(s) - 1 while left <= right: if s[left == s[right]: return left left += 1 right -= 1 return -1 ``` 接下来是Leetcode 977题,题目要求对给定的有序数组中的元素进行平方,并按照非递减的顺序返回结果。这里由于数组已经是有序的,所以可以使用双指针的方法来解决问题。一个指针指向数组的开头,另一个指针指向数组的末尾。通过比较两个指针所指向的元素的绝对值的大小来确定哪个元素的平方应该放在结果数组的末尾。具体实现的代码如下: ```python def sortedSquares(self, nums: List[int]) -> List[int]: left = 0 right = len(nums) - 1 ans = [] while left <= right: if abs(nums[left]) >= abs(nums[right]): ans.append(nums[left ** 2) left += 1 else: ans.append(nums[right ** 2) right -= 1 return ans[::-1] ``` 最后是Leetcode 209题,题目要求在给定的数组中找到长度最小的子数组,

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值