数组理论基础
-
数组是存放在连续内存空间上的相同类型数据的集合
- 数组的下标从0开始
- 数组的内存空间是连续的
-
因为数组的内存空间地址是连续的,所以删除/添加元素的时间复杂度是O(n)
-
数组的元素是不能删的,只能覆盖。
-
不同语言对于数组的实现是不一样的
704. 二分查找
二分查找的区间问题
左闭右闭
-
赋初值:
left, right = 0, len(nums) - 1因为是闭区间,所以左右指针都应该指向能取到的区间。(数组的index范围
[0, len(num-1)]) -
while循环更新:
left = mid + 1;right = mid - 1因为判断条件是
target和nums[mid]比较,当结果是不等时才进行更新,所以mid是不应该存在于下次循环的查找区间范围的,所以left和right都不取mid的值 -
while条件判断:
left <= right因为左右闭区间,右指针指向的index是左指针可以取到的,所以是小于等于
左闭右开
-
赋初值:
left, right = 0, len(nums)因为是右开,所以右指针应该指向能取到的区间+1的地方。
-
while循环更新:
left = mid + 1;right = mid因为判断条件是
target和nums[mid]比较,当结果是不等时才进行更新,所以mid是不应该存在于下次循环的查找区间范围的。因为右是开区间,所以右指针应该指向取不到的mid。 -
while条件判断:
left < right因为右是开区间,右指针指向的index是左指针取不到,所以不是小于等于
区间左闭右闭
# Time complexity: O(logN)
# Space complexity: O(1)
class Solution:
def search(self, nums: List[int], target: int) -> int:
left, right = 0, len(nums) - 1
while left <= right:
# floor division
mid = (left + right) // 2
if target < nums[mid]:
right = mid - 1
elif target > nums[mid]:
left = mid + 1
else:
return mid
return -1
区间左闭右开
class Solution:
def search(self, nums: List[int], target: int) -> int:
left, right = 0, len(nums)
while left < right:
# floor division
mid = (left + right) // 2
if target < nums[mid]:
right = mid
elif target > nums[mid]:
left = mid + 1
else:
return mid
return -1
27. 移除元素
暴力解法:双循环
- 第一层循环找到等于val的元素的下标
- 第二层循环将等于val的元素后面的全部元素前移一格,覆盖掉等于val的元素,实现删除
# Time complexity: O(N^2)
# Space complexity: O(1)
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
count = len(nums)
i = 0
while i < count:
if nums[i] == val:
count -= 1
for j in range(i, count):
nums[j] = nums[j+1]
else:
i += 1
return count
快慢指针
- 将原数组的前k个位置看作是新数组,用慢指针去数新数组的长度
- 快指针遍历原数组找到属于新数组的元素,并按照顺序插入新数组(慢指针指向的下标是新数组的尾部)
# Time complexity: O(N)
# Space complexity: O(1)
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
# fast to find the elements that we need in the new array
# slow count the number of elements in the new array (len(new) = len(old) - len(delete))
slow = 0
for fast in range(len(nums)):
if nums[fast] != val:
nums[slow] = nums[fast]
slow += 1
return slow
相向指针
- 左指针找需要删除的元素,右指针找下标最大的新数组元素
- 直到遍历完整个数组
# Time complexity: O(N)
# Space complexity: O(1)
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
left, right = 0, len(nums)
while left < right:
if nums[left] == val:
right -= 1
nums[left] = nums[right]
else:
left += 1
return left