赞
踩
1.数组是存放在连续内存空间上的相同类型数据的集合
2.数组下标都是从0开始的。
3.数组内存空间的地址是连续的
4.因为数组的在内存空间的地址是连续的,所以在删除或者增添元素的时候,就难免要移动其他元素的地址。例如:
但其实数组的元素并不能删除,只能覆盖
查看二维数组地址的代码如下:
- def test_arr():
- array = [[0, 1, 2],
- [3, 4, 5]]
- for row in array:
- for elem in row:
- print(f"Element {elem}: Address {id(elem)}")
输出结果为:
- Element 0: Address 140707786699664
- Element 1: Address 140707786699696
- Element 2: Address 140707786699728
- Element 3: Address 140707786699760
- Element 4: Address 140707786699792
- Element 5: Address 140707786699824
相邻元素之间的地址相差32位,8位为一个字节,所以每个元素之间相差4个字节,因为定义的是int型的数组。
二分法使用前提:
1.必须为有序数组
2.数组中无重复元素(若存在重复元素,则返回的下标可能不唯一)
重点:区间的定义就是不变量。要在二分查找的过程中,保持不变量,就是在while寻找中每一次边界的处理都要坚持根据区间的定义来操作,这就是循环不变量规则。
写二分法,区间的定义一般为两种,左闭右闭即[left, right],或者左闭右开即[left, right)。
①左闭右闭法:定义target在[left,right]区间中
- class Solution:
- def search(self, nums: List[int], target: int) -> int:
- left, right = 0, len(nums) - 1 # 左闭右闭,此时right要取最右边的值,所以为len-1
- while left <= right: # 左闭右闭情况下left==right仍是有效区间,需要考虑相等的情况
- middle = (left + right) // 2 # 左右相加除2取整
- if nums[middle] < target:
- left = middle + 1 # 此时middle的值<target,所以在下一阶段中应该舍弃,需要+1
- elif nums[middle] > target:
- right = middle - 1 # 同上,右端点-1舍弃middle的值
- else:
- return middle
- return -1
②左闭右开法:定义target在[left,right)区间中
- class Solution:
- def search(self, nums: List[int], target: int) -> int:
- left, right = 0, len(nums) # 此处由于是左闭右开,right不包含在区间内,所以直接取len
- while(left < right): # 左闭右开情况下不存在left==right的情况,所以用<
- middle = (left + right) // 2
- if nums[middle] < target:
- left = middle + 1 # 同左闭右闭法
- elif nums[middle] > target:
- right = middle # 由于right不包含在区间内,所以不用舍弃middle,不需要-1
- else:
- return middle
- return -1
数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖。
采用暴力解法,需要两层循环,一层用来遍历数组,另一层用来从后往前逐个覆盖。时间复杂度为O(n^2),在力扣上可以AC。
- class Solution:
- def removeElement(self, nums: List[int], val: int) -> int:
- i, size = 0, len(nums)
- while i < size:
- if nums[i] == val:
- for j in range(i + 1, size):
- nums[j - 1] = nums[j]
- i -= 1
- size -= 1
- i += 1
- return size
若追求更低的时间复杂度,则考虑双指针法,通过使用快慢两个指针在一层循环下完成任务。
快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
慢指针:指向更新 新数组下标的位置
删除过程示意图及代码如下
- class Solution:
- def removeElement(self, nums: List[int], val: int) -> int:
- fast, slow = 0, 0 # 定义快慢两个指针
- for fast in range(len(nums)):
- # 只有在不等于的情况下才会进行覆盖,因为fast寻找的是非目标元素,slow则用来保存非目标元素所在的下标
- if nums[fast] != val:
- nums[slow] = nums[fast]
- slow += 1
- return slow
这样的方法并不会改变元素的相对位置,且时间复杂度仅为O(n) 。
如果题目中元素的相对位置可以改变,并且要求移动的次数尽可能少,那么可以采用如下方法。采用两个指针分别指向数组的头和尾,然后从左边分别查找与val相同的元素,从右边查找与val不同的元素。然后用右侧不等于val的元素来覆盖左侧等于val的元素。
- class Solution:
- def removeElement(self, nums: List[int], val: int) -> int:
- if nums is None or len(nums)==0:
- return 0
- l=0
- r=len(nums)-1
- while l<r:
- while(l<r and nums[l]!=val):
- l+=1
- while(l<r and nums[r]==val):
- r-=1
- nums[l], nums[r]=nums[r], nums[l]
- print(nums)
- if nums[l]==val:
- return l
- else:
- return l+1
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。