金融本转计算机研0,掌握的比较好的是C++,由于未来三年使用更多的是python,就用python,试图不学语法就来刷题,不懂的边查。本博客不打算用写题解的方式,相信官方题解已经足够满足大伙的需求,更多用来记录心得和一些触动我的细节,希望可以得到带佬们的指导!
今天完成数组章节的
1、二分法中当区间为左闭右闭[left,right]时,while left <= right的=必不可少,因为left == right是有意义的,比如输入nums=[5],target=5,对应的输出非空
class Solution(object):
def search(self, nums, target): # 左闭右闭写法
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
left = 0
right = len(nums) - 1
while left <= right:
mid = (left + right) // 2
if nums[mid] == target:
return mid
elif nums[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1
if __name__ == '__main__':
s = Solution()
array = list([-1, 0, 3, 5, 9, 12])
target = 2
print(s.search(array, target))
2、掌握了一种左闭右开[left,right)的方法,即while left < right对应else: right = mid
class Solution(object):
def search(self, nums, target): # 左闭右开写法
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
left = 0
right = len(nums)
while left < right:
mid = (left + right) // 2
if nums[mid] == target:
return mid
elif nums[mid] < target:
left = mid + 1
else:
right = mid
return -1
if __name__ == '__main__':
s = Solution()
print(s.search(nums=[-1, 0, 3, 5, 9, 12], target=2))
3、在34 在排序数组中查找元素的第一个和最后一个位置中,掌握了一种在有序数列中(当然二分就是有序数组,前面忘写:)寻找相同元素的左边界和右边界的方法。
找边界问题可以从我们的35 搜索插入位置开始想,找得到nums[mid] == target,直接返回,找不到返回第一个比它大的元素或返回比他小的第一个元素再加1,我们关注找不到的情况,针对这几行
while left <= right:
mid = (left + right) // 2
if nums[mid] == target:
return/break
elif nums[mid] < target:
left = mid + 1
else:
right = mid - 1
以往一直找不到到底取的是left还是right还是left±1还是right±1,那么下面一劳永逸解决掉
最直观的理解是,结局总是停止在right == left - 1,那么之所以会以这种方式跳出循环,要么target比[nums[left], nums[right]]小,那最后一步就是right = mid - 1(称之为左跳出);要么target比[nums[left], nums[right]]大,那最后一步就是left = mid + 1(称之为右跳出);
若是右跳出,则上一步是left == mid == right,且nums[mid] == nums[left] < target,那么right就是跳出循环前最后一个小于target的元素;所以元素应该放在right+1也就是left处
若是左跳出,则上一步是left == mid == right或right-1,且nums[mid] == nums[left] > target,那么left就是跳出循环前最后一个大于target的元素;元素应该放在left处,然后把从left开始的元素一律向后移
要注意,我们位于[left,right]区间时,任何超出这个区间的我们都可认为是看不见的,去访问区间外的数据都是僭越!这就是为什么我们在右跳出时,我们要强调right,从而计算right+1(虽然right+1==left)而不是直接说应该放在left,因为此时left超出原有区间,访问left可能导致越界(虽然不会去访问它);这就是为什么我们在左跳出时,要强调left,而不是强调right,再用right+1(虽然right+1==left),因为此时right此时超出原有区间,访问nums[right]可能导致越界(虽然我们不会访问它)。
ok,接下来让我们开始找边界
首先找右边界,首先是当我们遇到nums[mid]==target的时候,continue,我们可以直接在判断语句上做手脚,让left尽可能向右移动,于是if nums[mid] <= target: left = mid + 1,接下来是跳出,不管是左跳出还是右跳出,上面说到left是第一个比他大的,那么right == left - 1就是最后一个小于等于他的,返回一个right(此时是僭越态,以为right只会减小,需要判断right是否大于等于0,其实都判断了也不会有问题)
接下来找左边界,同样地,遇到nums[mid]==target的时候continue,直接在判断语句上做手脚,让right尽可能向左移动,于是if nums[mid] >= target: right = mid - 1,接下来是跳出,不管是左跳出还是右跳出,上面说到right是第一个小于他的,那么right + 1 == left就是最后一个小于等于他的,返回一个left(此时是僭越态,因为left只会增大,需要判断left是否小于等于len - 1,其实都判断了也不会有问题)
这道题目的第一种方法是随便找到任何位置的这个元素,然后向左右扩展找边界,复杂度达到O(n),我想这是最直观最暴力的(当然也有更暴力的直接整个开始搜,这就不在我们的高雅范围内了哈:);第二种方法是两次二分分别找到两个边界,找两个边界也就是我上面提到的这堆玩意儿
方法一
class Solution(object):
def searchRange(self, nums, target): # 寻找到元素后左右找边界:复杂度On
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
loc = -1
left = 0
right = len(nums) - 1
while left <= right:
mid = (left + right) // 2
if nums[mid] == target:
loc = mid
break
elif nums[mid] < target:
left = mid + 1
else:
right = mid - 1
loc_s = loc_e = -1
if loc != -1:
loc_s = loc_e = loc
while loc_s >= 0 and nums[loc_s] == target:
loc_s -= 1
loc_s += 1
while loc_e < len(nums) and nums[loc_e] == target:
loc_e += 1
loc_e -= 1
return loc_s, loc_e
if __name__ == '__main__':
s = Solution()
loc_s, loc_e = s.searchRange(nums = [], target = 0)
print(loc_s, loc_e)
方法二
class Solution(object):
def searchRange(self, nums, target):
loc_s = loc_e = -1
# 找右边界
left = 0
right = len(nums) - 1
while left <= right:
mid = (left + right) // 2
if nums[mid] <= target:
left = mid + 1
else:
right = mid - 1
loc_e = right if 0 <= right < len(nums) and nums[right] == target else -1
# 找左边界
left = 0
right = len(nums) - 1
while left <= right:
mid = (left + right) // 2
if nums[mid] >= target:
right = mid - 1
else:
left = mid + 1
loc_s = left if 0 <= left < len(nums) and nums[left] == target else -1
return loc_s, loc_e
if __name__ == '__main__':
s = Solution()
loc_s, loc_e = s.searchRange(nums = [], target = 0)
print(loc_s, loc_e)
4、27 移除元素我采用的是双指针方法,准确的是存储两个指针间的差距以及其中一个指针的位置来实现双指针的方法,没啥的,浅浅一贴代码
class Solution(object):
def removeElement(self, nums, val):
"""
:type nums: List[int]
:type val: int
:rtype: int
"""
num_del = 0
for i in range(len(nums)):
if nums[i] == val:
num_del += 1
else:
nums[i - num_del] = nums[i]
return len(nums) - num_del