数组理论基础
文章链接:代码随想录 - 数组理论基础
数组是存放在连续内存空间上的相同类型数据的集合。
需要注意的点:
1、数组下标都是从0开始的
2、数组内存空间的地址是连续的
正是因为数组的在内存空间的地址是连续的,所以我们在删除或者增添元素的时候,就难免要移动其他元素的地址。数组的元素是不能删的,只能覆盖。
704. 二分查找
补充知识:
时间复杂度:时间复杂度的计算并不是计算程序具体运行的时间,而是算法执行语句的次数。
空间复杂度:空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度。
使用二分法的前提:1、数组为有序数组;2、数组中无重复元素。
二分法的本质:根据是否满足题目的条件来缩小答案所在的区间。
使用二分法需要注意区间:
当 l = 0,r = n 的时候因为 r 这个值我们在数组中无法取到,while(l < r) 是正确写法
当 l = 0,r = n-1 的时候因为 r 这个值我们在数组中可以取到,while(l <= r) 是正确写法,主要看能不能取到这个值
这是我写的程序:
class Solution:
def search(self, nums: List[int], target: int) -> int:
left = 0
right = len(nums)-1
while left <= right:
# middle = int((left+right)/2)
middle = left + ((right - left) // 2); # 防止溢出 等同于(left + right)/2
if nums[middle] < target: left = middle+1
elif nums[middle] > target: right = middle-1
else: return middle
return -1
调试过程中出现的问题:
- 最开始我取的middle为:middle = (left + right) / 2,报错,原因是middle有可能取到小数,这不同于c语言,正确的语句应为:middle = int(( left + right ) / 2) 或者 middle = int(( left + right ) // 2) ,另外为了防止溢出的问题,如果left + right 大于INT_MAX(C++内,就是int整型的上限),有更好的表达: mid = left + (right - left) // 2
27. 移除元素
本质:我们拿 right 的元素也就是右边的元素,去填补 left 元素也就是左边的元素的坑。
暴力算法:
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
# # 暴力算法
size = len(nums)
for i in range(len(nums)):
i = i - (len(nums)-size) # 更新i,因为随着元素的去除,i也要随着往前移动
if nums[i] == val:
for j in range(i, len(nums)-1):
nums[j] = nums[j+1]
nums[j+1] = 0
# i -= 1 # 这很关键,这在python中行不通
size -= 1
return size
调试过程中出现的问题:
- 参照原来的C++程序,在第二个 for 循环中添加 i -= 1 实际中不起作用,故在第一个 for 循环之后更新 i :i = i - ((len(nums) - size)
双指针解法:
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
# 双指针解法
fast = 0 # 快指针:寻找新数组的元素的值
slow = 0 # 满指针:记录新数组的元素的下标
while fast < len(nums):
# (等于val的值不进入新数组,所以遇到等于val的值,slow不更新)
if nums[fast] != val:
nums[slow] = nums[fast]
slow += 1
fast += 1
return slow # slow最后得到的值是新数组的元素的最后一个下标+1,即为新数组的长度
- 快指针可以理解成在旧数组中找非目标元素,然后赋值给慢指针指向的新数组,这两者都指向通一个数组。