给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
示例 1: 给定 nums = [3,2,2,3], val = 3, 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 你不需要考虑数组中超出新长度后面的元素。
示例 2: 给定 nums = [0,1,2,2,3,0,4,2], val = 2, 函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。
双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。
定义快慢指针
快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
慢指针:指向更新 新数组下标的位置
(版本一)快慢指针法
class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
# 快慢指针
fast = 0 # 快指针
slow = 0 # 慢指针
size = len(nums)
while fast < size: # 不加等于是因为,a = size 时,nums[a] 会越界
# slow 用来收集不等于 val 的值,如果 fast 对应值不等于 val,则把它与 slow 替换
if nums[fast] != val:
nums[slow] = nums[fast]
slow += 1
fast += 1
return slow
给你一个有序数组 nums ,请你原地删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。
示例 1:
给定数组 nums = [1,1,2],
函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。
你不需要考虑数组中超出新长度后面的元素。 示例 2:
给定 nums = [0,0,1,1,1,2,2,3,3,4],
函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
#第一个指针用于更改值
first = 0
#第二个指针用于遍历
for second in range(len(nums)):
#如果和之前记录的值不同
if nums[first] != nums[second]:
#第一个指针先加1
first += 1
#然后赋值
nums[first] = nums[second]
return first+1
概述:给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。请注意 ,必须在不复制数组的情况下原地对数组进行操作。
输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]
输入: nums = [0]
输出: [0]
方法一:快慢指针
思路:核心思路就是遇到 0 时,两两交换,区间上限快指针。需要注意原数组已经是有序的。
快慢指针
核心思路就是遇到 0 时,两两交换,区间上限快指针。
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
n = len(nums)
left, right = 0, 0
while right < n:
if nums[right] != 0:
nums[left], nums[right] = nums[right], nums[left]
left += 1
right += 1
给定 S 和 T 两个字符串,当它们分别被输入到空白的文本编辑器后,判断二者是否相等,并返回结果。 # 代表退格字符。
**注意:**如果对空文本输入退格字符,文本继续为空。
输入:S = “ab#c”, T = “ad#c”
输出:true
解释:S 和 T 都会变成 “ac”。
输入:S = “ab##”, T = “c#d#”
输出:true
解释:S 和 T 都会变成 “”。
输入:S = “a##c”, T = “#a#c”
输出:true
解释:S 和 T 都会变成 “c”。
输入:S = “a#c”, T = “b”
输出:false
解释:S 会变成 “c”,但 T 仍然是 “b”。
class Solution:
def backspaceCompare(self, S: str, T: str) -> bool:
def text_input(text):
# 栈
stack = []
# 遍历字符串
for ch in text:
# 普通字符入栈
if ch != "#":
stack.append(ch)
# "#" 字符且栈非空时,弹出
elif stack:
stack.pop()
return ''.join(stack)
# 判断两者是否相同
return text_input(S) == text_input(T)
class Solution:
def backspaceCompare(self, S: str, T: str) -> bool:
# 定义指针,p 指向 S 末尾,q 指向 T 末尾
p = len(S) - 1
q = len(T) - 1
# 定义变量 cnt_S,cnt_T,分别 '#' 的数量变化
cnt_S = 0
cnt_T = 0
while p >= 0 or q >= 0:
# 先遍历字符串 S
while p >= 0:
# 字符为 '#',cnt_S 加 1,同时 p 指针往左移动
if S[p] == '#':
cnt_S += 1
p -= 1
# 字符不为 '#',且 cnt_S 不为 0,当前字符要删除,更新 cnt_S,移动 p 指针
elif cnt_S > 0:
cnt_S -= 1
p -= 1
# 为普通字符,且 cnt_S 为 0,跳出循环,等待判断
else:
break
# 遍历字符串 T
# 逻辑与上面相同
while q >= 0:
if T[q] == '#':
cnt_T += 1
q -= 1
elif cnt_T > 0:
cnt_T -= 1
q -= 1
else:
break
# 此时判断两指针对应的字符
# 字符串都未遍历完的情况
if p >= 0 and q >= 0:
# 对应字符不同,直接返回 False
if S[p] != T[q]:
return False
# 字符串只有一个遍历完的情况
elif p >= 0 or q >= 0:
return False
# 上面情况不满足时,需要继续判断,继续移动 p, q 指针
p -= 1
q -= 1
return True
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
示例 1:
输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100],排序后,数组变为 [0,1,9,16,100]
示例 2:
输入:nums = [-7,-3,2,3,11]
输出:[4,9,9,49,121]
数组其实是有序的, 只不过负数平方之后可能成为最大数了。 那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。
此时可以考虑双指针法了,i指向起始位置,j指向终止位置。 定义一个新数组result,和A数组一样的大小,让k指向result数组终止位置。如果A[i] * A[i] < A[j] * A[j] 那么result[k–] = A[j] * A[j]; 。 如果A[i] *
A[i] >= A[j] * A[j] 那么result[k–] = A[i] * A[i]; 。
(版本一)双指针法
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
l, r, i = 0, len(nums)-1, len(nums)-1
res = [float('inf')] * len(nums) # 需要提前定义列表,存放结果
while l <= r:
if nums[l] ** 2 < nums[r] ** 2: # 左右边界进行对比,找出最大值
res[i] = nums[r] ** 2
r -= 1 # 右指针往左移动
else:
res[i] = nums[l] ** 2
l += 1 # 左指针往右移动
i -= 1 # 存放结果的指针需要往前平移一位
return res
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。
示例:
输入:s = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
提示:
1 <= target <= 10^9
1 <= nums.length <= 10^5
1 <= nums[i] <= 10^5
滑动窗口
接下来就开始介绍数组操作中另一个重要的方法:滑动窗口。
所谓滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。
(版本一)滑动窗口法
class Solution:
def minSubArrayLen(self, s: int, nums: List[int]) -> int:
l = len(nums)
left = 0
right = 0
min_len = float('inf')
cur_sum = 0 #当前的累加值
while right < l:
cur_sum += nums[right]
while cur_sum >= s: # 当前累加值大于目标值
min_len = min(min_len, right - left + 1)
cur_sum -= nums[left]
left += 1
right += 1
return min_len if min_len != float('inf') else 0
给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
示例:
输入: 3 输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ]
class Solution:
def generateMatrix(self, n: int) -> List[List[int]]:
nums = [[0] * n for _ in range(n)]
startx, starty = 0, 0 # 起始点
loop, mid = n // 2, n // 2 # 迭代次数、n为奇数时,矩阵的中心点
count = 1 # 计数
for offset in range(1, loop + 1) : # 每循环一层偏移量加1,偏移量从1开始
for i in range(starty, n - offset) : # 从左至右,左闭右开
nums[startx][i] = count
count += 1
for i in range(startx, n - offset) : # 从上至下
nums[i][n - offset] = count
count += 1
for i in range(n - offset, starty, -1) : # 从右至左
nums[n - offset][i] = count
count += 1
for i in range(n - offset, startx, -1) : # 从下至上
nums[i][starty] = count
count += 1
startx += 1 # 更新起始点
starty += 1
if n % 2 != 0 : # n为奇数时,填充中心点
nums[mid][mid] = count
return nums
class Solution:
def generateMatrix(self, n: int) -> [[int]]:
nums = [[0] * n for _ in range(n)]
rows = len(nums)
cols = len(nums[0])
top = 0
left = 0
bottom = rows -1
right = cols -1
res = []
count = 1
while True:
for i in range(left, right + 1):
nums[top][i] = count
count += 1
top += 1
if top > bottom:
break
for i in range(top, bottom + 1):
nums[i][right] = count
count += 1
right -= 1
if left > right:
break
for i in range(right, left -1 , -1):
nums[bottom][i] = count
count += 1
bottom -= 1
if top > bottom:
break
for i in range(bottom, top - 1 , -1):
nums[i][left] = count
count += 1
left += 1
if left > right:
break
return nums
你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示,其中 fruits[i] 是第 i 棵树上的水果种类 。
你想要尽可能多地收集水果。然而,农场的主人设定了一些严格的规矩,你必须按照要求采摘水果:
你只有两个篮子,并且每个篮子只能装单一类型的水果。每个篮子能够装的水果总量没有限制。
你可以选择任意一棵树开始采摘,你必须从每棵树(包括开始采摘的树)上恰好摘一个水果 。采摘的水果应当符合篮子中的水果类型。每采摘一次,你将会向右移动到下一棵树,并继续采摘。
一旦你走到某棵树前,但水果不符合篮子的水果类型,那么就必须停止采摘。
给你一个整数数组 fruits ,返回你可以收集的水果的最大数目。
题目很长有点繁琐,先中译中一下:
给定一个数组 fruit[ ],找出该数组中连续的包含两个不同数字的最大子串,返回最大子串长度
如: fruits = [3,3,3,1,2,1,1,2,3,3,4] 输出:5 (因为最大子串为 [1,2,1,1,2])
思路:
若该数组中只有一个数字,则最大子串为其本身,返回长度为1
设置左右两个指针和一个列表s,设置result用于存储最大字串长,该列表s初始化为给定数组的第一个元素,左右指针起始为0。若右指针所指的元素与前一位不同并且该元素不在s中,则将这个元素添加到s后,此时若s的长度大于2(即包含超过两个类别的数字)时,比较之前记录的result值与当前子串长度,取最大值更新result。移动左指针,若移动后的值和上一位相同,则再次向后移动左指针。
相当于是一个利用两个指针形成的伸缩滑动的窗口,碰到第三种元素时移动左窗口边界,比较找到串口最大长度。
class Solution:
def totalFruit(self, fruits: List[int]) -> int:
if len(fruits) == 1:
return 1
l = r = 0
s = [fruits[0]]
n = len(fruits)
result = 0
while r < n:
if fruits[r] != fruits[r - 1] and fruits[r]not in s:
s.append(fruits[r])
if len(s) > 2:
result = max(result, r - l)
l = r - 1
while fruits[l] == fruits[l - 1]:
l -= 1
s = [fruits[l], fruits[r]]
r += 1
return max(result, r - l)
#滑动窗口最大,且滑动窗口内只有两种数字
#核心:记录滑动窗口内的种类和出现的次数,这里我们用哈希表
#能用滑动窗口的题,都是要求在一段连续的子数组中
class Solution(object):
def totalFruit(self, fruits):
cnt = Counter()
left = ans = 0
for right, x in enumerate(fruits):#这里枚举是关键
cnt[x] += 1
while len(cnt) > 2:#种类超过2时就应该判断
cnt[fruits[left]] -= 1#这里,先对left这个种类的个数-1
if cnt[fruits[left]] == 0:#然后再判断这个种类滑动窗口内数量是不是为0
cnt.pop(fruits[left])#如果为0了就移除这个种类
left += 1#然后顺势向前移动滑动窗口
ans = max(ans, right - left + 1)
return ans
给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。
注意:
对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
如果 s 中存在这样的子串,我们保证它是唯一的答案。
示例 1:
输入:s = “ADOBECODEBANC”, t = “ABC”
输出:“BANC”
解释:最小覆盖子串 “BANC” 包含来自字符串 t 的 ‘A’、‘B’ 和 ‘C’。
示例 2:
输入:s = “a”, t = “a”
输出:“a”
解释:整个字符串 s 是最小覆盖子串。
示例 3:
输入: s = “a”, t = “aa”
输出: “”
解释: t 中两个字符 ‘a’ 均应包含在 s 的子串中,
因此没有符合条件的子字符串,返回空字符串。
提示:
m == s.length
n == t.length
1 <= m, n <= 105
s 和 t 由英文字母组成
方法1:该方法主要使用的是滑动窗口思想,大概含义:
用left,right表示滑动窗口的左边界和右边界,通过改变i,j来扩展和收缩滑动窗口,可以想象成一个窗口在字符串上游走,当这个窗口包含的元素满足条件,即包含字符串T的所有元素,记录下这个滑动窗口的长度right-left
+1,这些长度中的最小值就是要求的结果具体实现过程如下:
(1)计算目标值t中每个char的个数,作为char的需求清单need,即需要need中k*v个char;
用处:当检索到滑动窗口中存在一个char时,就抵消掉need中对应的char值,即need[char] -1 ;当检索到窗口函数中不存在一个char时,就增加need中对应的char值,即need[char] +1 ;
(2)记录目标值t的长度,needCnt,即总共需要的字符串数,needCnt等于need中value的总和。
用处:取代遍历need,通过总数来判断滑动窗口是否包含了所有的t中char
(3)不断增加指针right使滑动窗口增大,直到窗口包含了T的所有元素:当窗口包含了所有的need字符(即needCnt=0),意味着可以剔除窗口括进来的不需要字符,这时可以缩小窗口了
(4)不断增加left,使滑动窗口缩小。因为是要求最小字串,所以将不必要的元素排除在外,使长度减小,直到碰到一个必须包含的元素(其实是清单need中必须包含的子串不能小于0,当=0时,意味着需求刚好满足),这个时候不能再扔了。再扔就不满足条件了,记录此时滑动窗口的left和right的值,right-left
+1,即是最小子串的长度。并保存最小值。(5)当right再增加一个位置,滑动窗口就不满足条件的时候,这是就要移动left,是滑动窗口增大,直至窗口包含了所有的need字符(即needCnt=0)。这时从步骤(3)从新来,寻找新的满足条件的滑动窗口,如此反复,直到left超出了字符串S范围。
class Solution:
def minWindow(self, s: str, t: str) -> str:
# 目标字符记录
need=collections.defaultdict(int)
for c in t:
need[c]+=1
# 目标字符长度
needCnt=len(t)
left=0
res=(0,float('inf'))
for r,c in enumerate(s):
if need[c]>0:
# 如果need[c]>0,意味着窗口搜索到目标值
needCnt-=1
# 目标值被搜索到,则need相应value-1,即用以记录搜索到need中字符的个数;
# =0代表搜索到的值和need值相同;<0代表need中同一个字符被多次搜索到;
# >0,代表need中该字符没有全部被遍历出来
need[c]-=1
if needCnt==0: # 滑动窗口包含了所有T元素
# 开始窗口函数内部的搜索
while True: # 移动滑动窗口右边界i,排除多余元素
c=s[left]
if need[c]==0:
# need[c]==0,break 情况,代表着这轮的滑动窗口不符合要求
break
# 窗口中字符和need相互抵消
need[c]+=1
left+=1
if r-left <res[1]-res[0]: #记录结果
res=(left,r)
# 窗口函数内部计算完后,向下一步迭代
# s[left]是目标集中t的字符,这时从窗口函数清除,
# 则意味着窗口函数需要新的字符填充,即need[s[left]]和needCnt需要加一
need[s[left]]+=1 # left增加一个位置,寻找新的满足条件滑动窗口
needCnt+=1
# 新一轮的右边界
left+=1
return '' if res[1]>len(s) else s[res[0]:res[1]+1] #如果res始终没被更新过,代表无满足条件的结果
题目
给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
示例 :
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]
想法
@厨子哥
1、4根线,遍历一层剥掉一层。
2、每次有线移动则判断是否出界。
实现
方法1:python
class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
row=len(matrix)
col=len(matrix[0])
left,top=0,0
right,bottom=col-1,row-1
out=list()
while True:
for i in range(left,right+1):
out.append(matrix[top][i])
top+=1
if top>bottom:
break
for i in range(top,bottom+1):
out.append(matrix[i][right])
right-=1
if left>right:
break
for i in range(right,left-1,-1):
out.append(matrix[bottom][i])
bottom-=1
if top>bottom:
break
for i in range(bottom,top-1,-1):
out.append(matrix[i][left])
left+=1
if left>right:
break
return out
与54题一样