题目704.二分查找.
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
题目中的前提条件有:
1.数组为有序数组
2.数组中无重复元素
数组有序是使用二分法的前提,而且如果有重复元素,二分查找返回的元素下标可能不是唯一的,这些都是使用二分法的前提,看到题目满足如上条件时,可以考虑一下是不是可以使用二分法。
二分法的思想虽然简单,但涉及边界条件,需要清楚定义区间,也就是定义不变量,在二分查找的过程中(即while),每一次边界的处理都要坚持根据区间的定义来操作。
一般来说可以使用左闭右闭,即[left,right],定义target在这个区间里。
因此需要注意以下两点:
题解:
class Solution:
def search(self, nums: List[int], target: int) -> int:
left, right = 0, len(nums) - 1
while left <= right:
mid = (left + right) // 2
if nums[mid] == target:
return mid
elif nums[mid] > target:
right = mid - 1
else:
left = mid + 1
return -1
理解之后可以做一下以下题目:
35.搜索插入位置.
34. 在排序数组中查找元素的第一个和最后一个位置.
69. x 的平方根.
367. 有效的完全平方数.
题目: 27. 移除元素.
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
如何删除数组中的元素?
数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖。
直观的做法就是暴力解法,一个for循环遍历数组,一个for循环更新数组,发现要移除的元素就将其后方数组集体向前移动。
很明显暴力解法的时间复杂度是O(n^2),通常我们可以用到快慢指针的方法,在一个循环内完成两个循环的工作。
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
if len(nums) == 0:
return 0
i = 0 #指向要赋值的位置
for j in range(len(nums)):
if nums[j] != val: #当前要处理的元素不等于val,即为输出数组中的一个元素
nums[i] = nums[j] #把输出数组直接写在输入数组上
i += 1 #指针右移
return i
双指针法相关题目:
26. 删除有序数组中的重复项.
283. 移动零.
977. 有序数组的平方.
题目209. 长度最小的子数组.
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
暴力解法,使用两个for循环,不断寻找符合条件的子序列。这里可以使用数组操作的另一种方法:滑动窗口。
滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。滑动窗口也可以理解为双指针法的一种!只不过这种解法更像是一个窗口的移动,所以叫做滑动窗口更适合一些。
滑动窗口主要需要确定三点内容:
对于本题,窗口就是 满足其和 ≥ target 的长度最小的 连续 子数组。
窗口的起始位置如何移动:如果当前窗口的值大于target了,窗口就要向前移动了(也就是该缩小了)。
窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,窗口的起始位置设置为数组的起始位置就可以了。
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
res = float("inf") #要选出长度最小的,先定义一个无限大的值
sum = 0 #滑动窗口数值之和
i = 0 #滑动窗口起始位置
sub_len = 0 #滑动窗口长度
for j in range(len(nums)):
sum += nums[j]
#用while每次更新起始位置,并比较子序列是否符合条件
while sum >= target:
sub_len = j - i + 1
res = min(res, sub_len)
#变更子序列的起始位置
sum -= nums[i]
i += 1
return 0 if res == float("inf") else res
最长窗口模板
for(枚举选择)
右边界
while(不符合条件)
左边界
更新结果
题目: 59. 螺旋矩阵 II.
给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。
输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]
模拟行为并不涉及到什么算法,就是模拟过程,但却十分考察对代码的掌控能力。
模拟顺时针画矩阵的过程:
由外向内一圈一圈这么画下去,每一圈都要按照统一的规则(左闭右开,或者左开右闭的原则)。
class Solution:
def generateMatrix(self, n: int) -> List[List[int]]:
left, right, up, down = 0, n-1, 0, n-1
matrix = [[0] * n for _ in range(n)] #初始矩阵
num = 1
while left <= right and up <= down:
#填充左到右
for i in range(left, right+1):
matrix[up][i] = num
num += 1
up += 1
#填充上到下
for i in range(up, down+1):
matrix[i][right] = num
num += 1
right -= 1
#填充右到左
for i in range(right, left-1, -1):
matrix[down][i] = num
num += 1
down -= 1
#填充下到上
for i in range(down, up-1, -1):
matrix[i][left] = num
num += 1
left += 1
return matrix
相关题目:
54. 螺旋矩阵.