当前位置:   article > 正文

代码随想录学习Day 1

代码随想录学习Day 1

数组基础知识

1.数组是存放在连续内存空间上的相同类型数据的集合

2.数组下标都是从0开始的。

3.数组内存空间的地址是连续的

4.因为数组的在内存空间的地址是连续的,所以在删除或者增添元素的时候,就难免要移动其他元素的地址。例如:

但其实数组的元素并不能删除,只能覆盖

查看二维数组地址的代码如下:

  1. def test_arr():
  2. array = [[0, 1, 2],
  3. [3, 4, 5]]
  4. for row in array:
  5. for elem in row:
  6. print(f"Element {elem}: Address {id(elem)}")

输出结果为:

  1. Element 0: Address 140707786699664
  2. Element 1: Address 140707786699696
  3. Element 2: Address 140707786699728
  4. Element 3: Address 140707786699760
  5. Element 4: Address 140707786699792
  6. Element 5: Address 140707786699824

相邻元素之间的地址相差32位,8位为一个字节,所以每个元素之间相差4个字节,因为定义的是int型的数组。

704.二分查找

题目链接

讲解链接

二分法使用前提:
1.必须为有序数组

2.数组中无重复元素(若存在重复元素,则返回的下标可能不唯一)

重点:区间的定义就是不变量。要在二分查找的过程中,保持不变量,就是在while寻找中每一次边界的处理都要坚持根据区间的定义来操作,这就是循环不变量规则。

二分法,区间的定义一般为两种,左闭右闭即[left, right],或者左闭右开即[left, right)。

①左闭右闭法:定义target在[left,right]区间中

  1. class Solution:
  2. def search(self, nums: List[int], target: int) -> int:
  3. left, right = 0, len(nums) - 1 # 左闭右闭,此时right要取最右边的值,所以为len-1
  4. while left <= right: # 左闭右闭情况下left==right仍是有效区间,需要考虑相等的情况
  5. middle = (left + right) // 2 # 左右相加除2取整
  6. if nums[middle] < target:
  7. left = middle + 1 # 此时middle的值<target,所以在下一阶段中应该舍弃,需要+1
  8. elif nums[middle] > target:
  9. right = middle - 1 # 同上,右端点-1舍弃middle的值
  10. else:
  11. return middle
  12. return -1

②左闭右开法:定义target在[left,right)区间中

  1. class Solution:
  2. def search(self, nums: List[int], target: int) -> int:
  3. left, right = 0, len(nums) # 此处由于是左闭右开,right不包含在区间内,所以直接取len
  4. while(left < right): # 左闭右开情况下不存在left==right的情况,所以用<
  5. middle = (left + right) // 2
  6. if nums[middle] < target:
  7. left = middle + 1 # 同左闭右闭法
  8. elif nums[middle] > target:
  9. right = middle # 由于right不包含在区间内,所以不用舍弃middle,不需要-1
  10. else:
  11. return middle
  12. return -1

27.移除元素

题目链接

讲解链接

数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖

采用暴力解法,需要两层循环,一层用来遍历数组,另一层用来从后往前逐个覆盖。时间复杂度为O(n^2),在力扣上可以AC。

  1. class Solution:
  2. def removeElement(self, nums: List[int], val: int) -> int:
  3. i, size = 0, len(nums)
  4. while i < size:
  5. if nums[i] == val:
  6. for j in range(i + 1, size):
  7. nums[j - 1] = nums[j]
  8. i -= 1
  9. size -= 1
  10. i += 1
  11. return size

若追求更低的时间复杂度,则考虑双指针法,通过使用快慢两个指针在一层循环下完成任务。

快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组

慢指针:指向更新 新数组下标的位置

删除过程示意图及代码如下

  1. class Solution:
  2. def removeElement(self, nums: List[int], val: int) -> int:
  3. fast, slow = 0, 0 # 定义快慢两个指针
  4. for fast in range(len(nums)):
  5. # 只有在不等于的情况下才会进行覆盖,因为fast寻找的是非目标元素,slow则用来保存非目标元素所在的下标
  6. if nums[fast] != val:
  7. nums[slow] = nums[fast]
  8. slow += 1
  9. return slow

这样的方法并不会改变元素的相对位置,且时间复杂度仅为O(n) 。

如果题目中元素的相对位置可以改变,并且要求移动的次数尽可能少,那么可以采用如下方法。采用两个指针分别指向数组的头和尾,然后从左边分别查找与val相同的元素,从右边查找与val不同的元素。然后用右侧不等于val的元素来覆盖左侧等于val的元素。

  1. class Solution:
  2. def removeElement(self, nums: List[int], val: int) -> int:
  3. if nums is None or len(nums)==0:
  4. return 0
  5. l=0
  6. r=len(nums)-1
  7. while l<r:
  8. while(l<r and nums[l]!=val):
  9. l+=1
  10. while(l<r and nums[r]==val):
  11. r-=1
  12. nums[l], nums[r]=nums[r], nums[l]
  13. print(nums)
  14. if nums[l]==val:
  15. return l
  16. else:
  17. return l+1

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/555915
推荐阅读
相关标签
  

闽ICP备14008679号