学习内容: LC27 移除元素
个人思路:
猛的一看感觉很简单,感觉一个for就可以解决。仔细查看之后发现暗藏玄机。
- 首先可以直接判断当 nums[i] == val时,删除list当前索引的元素。 del nums[index]
- 当 nums[i] == val时,将其和最后一个数进行交换。
以上只是我当时能想到方法,但是这两种方法都要注意的是,如果用for进行遍历的话,删除或交换位置之后,i的值是会+1的,**这样会导致你下一次的判断是跳过了交换值的或跳过了删除值后一个值的。**所以针对这种情况,尽量使用条件语句对遍历变量i进行限制同时结合while语句进行遍历。
class Solution(object):
def removeElement(self, nums, val):
"""
:type nums: List[int]
:type val: int
:rtype: int
"""
res = 0
i = 0
while i != len(nums): # while结合if组合使用
if nums[i] == val:
tmp = nums[-1]
nums[-1] = val
nums[i] = tmp
nums.pop()
else:
res += 1
i += 1
return res
双指针方法
算法思路:思想如同上述思路2,就是将前面遍历出来的num[i]==val的值交换到数组末尾。设置两个指针fast和slow。其中fast用来从后先前寻找num[fast] != val的坐标,用slow从前往后来寻找nums[slow]==val的坐标,然后交换。
class Solution(object):
def removeElement(self, nums, val):
"""
:type nums: List[int]
:type val: int
:rtype: int
"""
if not nums or val not in nums:
return len(nums)
slow, fast = 0, len(nums)-1
while slow < fast:
while slow < fast and nums[slow] != val:
slow += 1
while slow < fast and nums[fast] == val:
fast -= 1
nums[slow], nums[fast] = nums[fast], nums[slow]
if nums[slow] == val:
return slow
else:
return slow + 1
PS:代码看起来和快速排序的思路一样。
其中if nums[slow] == val: return slow 是值得深思的。首先需要先分析,这一步的验证是否有必要,当我们结束while循环后的状态是,slow==fast,而nums[slow]或nums[fast]都是没有在上面代码中被判断过是否等于val的,所以我们需要验证nums[slow]是否等于val。
若nums[slow]==val 的话,说明nums[0:slow-1]都是返回值,所以数量为slow。反之,返回slow+1。
学习内容: LC977. 有序数组的平方
题目描述:
个人思路:
第一想法还是对nums平方后选择一种排序算法。
PS:编写过程中发现选择快速排序会导致超出时间限制,归并排序则正常。所以以后尽量使用归并排序。
双指针方法
算法思路:仍是确定两个指针,left和right。由于题目说输出非递减序列,所以输出的只要不是递减序列就可以,即我们只需要将大的数字尽可能地放在后面即可。大数后移则需要用到数字比较和数字交换。因此选用left指针从左向右遍历数字,right指针从右向左遍历数字。
因为这里需要用到交换+比较,如果用for进行遍历还是会导致后面转移到前面的数字是会跳过一次遍历的,导致错误。所以还是要选择while + 条件语句的遍历方法。
class Solution(object):
def sortedSquares(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
ans = [-1] * len(nums)
left, right = 0, len(nums)-1
k = len(nums) - 1
while left <= right:
ans1 = nums[left] ** 2
ans2 = nums[right] ** 2
if ans1 < ans2:
ans[k] = ans2
right -= 1
else:
ans[k] = ans1
left += 1
k -= 1
return ans
学习内容:LC209. 长度最小的子数组
题目描述:
首先我们需要注意要求:连续子序列和大于等于。
个人思路:
看到连续子序列的判断一般来说就可以想到滑动窗口。通常情况下,能想到的方法需要两个for循环,一个for用来遍历窗口大小,一个for用来移动窗口位置。但是,这就导致了时间复杂度很大,会超过时间限制。也可以将i,j看作是暴力枚举的起止指针。
for i in range(1, len(nums)+1): # 用来遍历窗口大小
for j in range(len(nums) - i): # 用来编辑窗口的开始位置
if sum(nums[j:j+i]) >= target:
return i
显然,这并不是一个好的解决方法。那如何使用一个for循环解决问题呢。
双指针方法\滑动窗口方法
首先只用一个for循环解决问题的话,就需要摒弃常规的思路,就是固定住滑窗的大小然后平行滑动。这必将使用到两个for循环。
1.我们不用长度来表示滑窗而使用窗口的起止位置来表示滑窗大小。
2.用for来固定终止位置,想办法再表示开始位置。
3.滑窗的移动方式不是固定长度的平移,而是先找到满足条件的长度,然后去除开头,直到不满足条件后,加入结尾。(比较难想象)
可以发现每次都是在已经满足条件的内部先去寻找仍满足条件的子序列,这样就可以保证能找到最短的子序列。
def minSubArrayLen(self, target, nums):
index = 0 # 起始索引
size = 0
res = float('inf')
for i in range(len(nums)): # 遍历了终止索引
size += nums[i] # 相当于将后面的元素加入到了滑窗内
while size >= target:
res = min(res, i-index+1)
size -= nums[index]
index += 1
if res == float('inf'):
return 0
else:
return res
PS.个人认为不能完全当作滑动窗口来看,其实是一种双指针的解法。但是要参考着滑窗的方式更容易理解。