代码随想录 day1

704 二分查找

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

示例 1:

输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4
示例 2:

输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1

提示:

你可以假设 nums 中的所有元素是不重复的。
n 将在 [1, 10000]之间。
nums 的每个元素都将在 [-9999, 9999]之间。

好久没有写数据结构相关代码了, 今天开始,决定坚持60天。

  1. 自己预习写二分法代码,写得有些凌乱,忘记了区间[ ], [ )的区别, 导致写出来的[ ]中,right = mid, 忽略了nums[mid] > target时, mid索引的值一定不会等于target, 且right是闭区间, 所以,如果right = mid, 则mid出现重复计算的情况, 需要修正为right = mid - 1.
  2. 看了carl哥的视频,理解整理如下:
    2.1 在使用二分法时,注意二分法的适用情况: nums数组有序 + 数值不重复。
    2.2 注意区间选择一定要保持不变, 即选择 [left, right] , 则在while 循环中, 一定要保证区间合法, 对于[ ], 则left=right是成立的; 但是 [left, right)情况下, left = right会导致集合区间不合法, 因为不存在一个数i, 使得i 包含在区间, 同时i又不包含在区间的情况。
    2.3 保证循环的不变性, 在循环中,对于left, right的更新要保证和定义区间 [], [)一致。

根据[left, right] 实现二分法

# 条件: nums 有序;
left = 0
right = len(nums) -1
while left <= right:
	mid = (left + right) // 2
	if nums[mid] < target:
		left = mid + 1  #表明target在右半区间, 需要更新左区间, 且左区间是闭区间, mid已经取过,且nums[mid]!=target, 所以, left = mid + 1
	elif nums[mid] > target:
		right = mid - 1
	else:
		return mid
return -1

根据[left, right) 实现二分法

left = 0
right = len(nums)   # 因为右边区间无法取到
while left < right:   # 区间定义为 [ ), left = right不合法
	mid = (left + right) // 2
	if nums[mid] < target:
		left = mid + 1  #表明target在右半区间, 需要更新左区间, 且左区间是闭区间, mid已经取过,且nums[mid]!=target, 所以, left = mid + 1
	elif nums[mid] > target:
		right = mid    # 因为右区间为开区间, 无法取到
	else:
		return mid
return -1

code python 1 []

from typing import List
class Solution:
    def search(self, nums: List[int], target: int) -> int:
        """
        条件: nums 有序;
        # [], [)
        """
        left, right = 0, len(nums)-1
        while left <= right:  # 区间 与限定一致
            mid = left + (right - left) // 2
            if nums[mid] == target:
                return mid
            elif nums[mid] < target:
                left = mid + 1
            else:
                right = mid - 1
        return -1

code python 2 [)

from typing import List
class Solution:
    def search(self, nums: List[int], target: int) -> int:
        """
        条件: nums 有序;
        # [)
        """
        left, right = 0, len(nums)
        while left < right:  # 区间 与限定一致
            mid = left + (right - left) // 2
            if nums[mid] == target:
                return mid
            elif nums[mid] < target:
                left = mid + 1
            else:
                right = mid
        return -1

小结,
5. [], [), 要注意右区间的取值, []: right = len(nums) -1, [): right = len(nums)
6. 为防止溢出, mid = (left + right) // 2 可以修正为 mid = left + (right -left) // 2

27. 移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。
然后返回 nums 中与 val 不同的元素的数量。
假设 nums 中不等于 val 的元素数量为 k,要通过此题,您需要执行以下操作:
更改 nums 数组,使 nums 的前 k 个元素包含不等于 val 的元素。nums 的其余元素和 nums 的大小并不重要。
返回 k。
用户评测:
评测机将使用以下代码测试您的解决方案:

int[] nums = [...]; // 输入数组
int val = ...; // 要移除的值
int[] expectedNums = [...]; // 长度正确的预期答案。
                            // 它以不等于 val 的值排序。
int k = removeElement(nums, val); // 调用你的实现

assert k == expectedNums.length;
sort(nums, 0, k); // 排序 nums 的前 k 个元素
for (int i = 0; i < actualLength; i++) {
    assert nums[i] == expectedNums[i];
}
如果所有的断言都通过,你的解决方案将会 通过。

示例 1:
输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2,_,_]
解释:你的函数函数应该返回 k = 2, 并且 nums 中的前两个元素均为 2。
你在返回的 k 个元素之外留下了什么并不重要(因此它们并不计入评测)。
示例 2:
输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,4,0,3,_,_,_]
解释:你的函数应该返回 k = 5,并且 nums 中的前五个元素为 0,0,1,3,4。
注意这五个元素可以任意顺序返回。
你在返回的 k 个元素之外留下了什么并不重要(因此它们并不计入评测)。
 
提示:

0 <= nums.length <= 100
0 <= nums[i] <= 50
0 <= val <= 100

我的理解:删除数组nums在值为val1的数据。

  1. 无脑操作,直接暴力求解。需要注意的是,删除当前nums[i]=val之后,所有索引>i的数据都需要前移动1位。数组的删除只可以覆盖实现, 因为数组的地址是连续的的。
    代码提交leetcode如下:
class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        # 暴力方法
        # 删除某一个元素, 其余所有元素都要前移
        if not nums: return 0
        rest = len(nums)
        i = 0
        while i < rest:
            if nums[i] != val:
                i += 1
            else:
                # for j in range(i, rest-1):
                #     nums[j] = nums[j+1]
                # nums[rest-1]='_'
                nums[i:rest-1]=nums[i+1:rest]
                rest -= 1
        return rest

2. 动点脑子,使用双指针。
题目的要求: 使 nums 的前 k 个元素包含不等于 val 的元素。nums 的其余元素和 nums 的大小并不重要。
只需要把nums[i]!=val的数据移动到数组nums的前面, ,你不需要考虑数组中超出新长度后面的元素。
需要一个东西记录k的位置, 另一个东西表示数组nums已经遍历完成。
left,right指针
right表示当前遍历到数组的最新位置。
left 遍历到right位置时,nums中不为val的索引位置。

> 双指针法
双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。
定义快慢指针
快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
慢指针:指向更新 新数组下标的位置
双指针法(快慢指针法)在数组和链表的操作中是非常常见的,很多考察数组、链表、字符串等操作的面试题,都使用双指针法。

code python 1

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        # 双指针
        left = 0
        right = len(nums)
        while left < right:
            if nums[left] != val:
                left += 1
            else:
                nums[left], nums[right-1] = nums[right-1], nums[left]
                right -= 1
        return left

code python 2

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        n = len(nums)
        left, right  = 0, n - 1
        while left <= right:
            while left <= right and nums[left] != val:  ## val = 7, nums=[7,7,7,7,3,53,5, 7,7,7,7]
                left += 1
            while left <= right and nums[right] == val:   ## val = 7, nums=[7,7,7,7,3,53,5, 7,7,7,7]
                right -= 1
            if left < right:           ## 此时nums[left]=3, nums[right]=5,一定不等于val=7, 且 left==right结束
                nums[left] = nums[right]
                left += 1
                right -= 1
        return left
  • 小结:
  1. 题目的要求决定了code
  2. 双指针的初始化要仔细考虑, 区间一致性, 循环的一致性
  • 下面的code来自代码随想录
(版本一)快慢指针法
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

code python 3 (二刷)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值