704.二分查找
文档讲解:https://programmercarl.com/%E6%95%B0%E7%BB%84%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html
视频讲解:https://www.bilibili.com/video/BV1fA4y1o715
状态:第4、5遍做了,思路较为清晰。本次顺带完成了相关题目。
思路
二分法前提条件:元素顺序排列;无重复。
主要知识点:循环不变量。
关于区间的界定:
- 如果假设target在闭区间[left,right]内,那么left<=right是有意义的。如果target<nums[mid],那么right的更新为mid-1.因为nums[mid]一定不是target。
- 如果假设target在左闭右开区间[left,right),那么left<=right没有意义,等号取不到。此时如果target<nums[mid],那么right的更新为mid.因为如果更新为mid-1,那mid-1这个值为区间的上限,取不到,就会少考虑这种可能。
代码:
版本一:左右都是闭区间
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 - left)//2 # 为了防止溢出
if nums[mid] > target:
right = mid - 1
elif nums[mid] < target:
left = mid + 1
else:
return mid
return -1
版本二:左闭右开
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 - left)//2 # 为了防止溢出
if nums[mid] > target:
right = mid
elif nums[mid] < target:
left = mid + 1
else:
return mid
return -1
35.搜索插入位置(二分查找相关题目)
题目链接:https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/
状态:思路较为明确,为了复习java,本次使用Java完成。
思路
本题相较于二分查找,要求变为了找不到的话就返回插入位置。考虑到在找不到的情形下,最终left
指针和right
指针总会经历一个重叠,交叉的过程。也就是说在最后一次进入循环更新完mid
后,存在以下情形:left=mid=right
。那么我们分析:当target
大于nums[mid]
时,应插入的位置为right+1
,也就是更新后的left
;当target
小于nums[mid]
时,应插入的位置为left
(将原本的数组向后挤一个位置)。因此,最后返回left
即可。
代码:
class Solution {
public int searchInsert(int[] nums, int target) {
int left = 0;
int right = nums.length-1;
int mid = 0;
while(left<=right){
mid = left+(right-left)/2;
if(target<nums[mid]){
right = mid-1;
}
else if(target>nums[mid]){
left = mid+1;
}
else{
return mid;
}
}
return left;
}
}
34.搜索插入位置(二分查找相关题目)
题目链接:https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/
状态:思路较为明确,为了复习java,本次使用Java完成。代码整体不够精炼,Java使用熟练度较低,多多练习。
思路
本题在二分查找的基础上,增加了窗口滑动,确定相同元素的范围区间,注意不要数组越界就好。
代码:
class Solution {
public int[] searchRange(int[] nums, int target) {
int left = 0;
int right = nums.length-1;
int ans = -1;
int[] ansArr = new int[]{-1,-1};
while(left <= right){
int mid = left + (right - left) / 2;
if(nums[mid] > target){
right = mid - 1;
}
else if(nums[mid] < target){
left = mid + 1;
}
else{
ans = mid;
break;
}
}
if(ans==-1){
return ansArr;
}
for(int i = ans; i>=0;i--){
if(nums[i]==target){
ansArr[0]=i;
}
else{
break;
}
}
for(int i = ans;i<nums.length;i++){
if(nums[i]==target){
ansArr[1] = i;
}
else{
break;
}
}
return ansArr;
}
}
27.移除元素
文档讲解:https://programmercarl.com/0027.%E7%A7%BB%E9%99%A4%E5%85%83%E7%B4%A0.html
视频讲解:https://www.bilibili.com/video/BV12A4y1Z7LP
状态:第4、5遍做了,思路较为清晰。
思路
主要思路是双指针:
- 两个指针,分别为快指针和慢指针。快指针负责遍历数组,判断情况,慢指针负责维护更新数组。
代码:
class Solution(object):
def removeElement(self, nums, val):
"""
:type nums: List[int]
:type val: int
:rtype: int
"""
fast = 0
slow = 0
for fast in range(len(nums)):
if nums[fast]!=val:
nums[slow]=nums[fast]
slow+=1
fast+=1
return slow