704 二分查找、
状态:完成
该题是一道经典的二分查找问题,时间复杂度O(logn)。循环条件中的left<=right是否取等是关键,边界条件的判定看取等之后进循环还有意义吗,取等之后是有意义的因为遍历没有遍历过。三种情况的取值也是关键。
public int search(int[] nums, int target) {
int left=0;
int right=nums.length-1;
int mid = left + (right-left)/2;
//这里取等表示left==right时是有意义的
while(left<=right){
mid = left + (right-left)/2;
//先判断一下target是不是nums[left]跟nums[right]
if(target==nums[left]&&target==nums[right]){
return target==nums[left]?left:right;
}
//分三种情况 target大于nums[mid],target小于,target等于
if(target>nums[mid]){
left=mid+1;//mid肯定不是target
}else if(target<nums[mid]){
right=mid-1;//mid肯定不是target
}else if(target==nums[mid]){
return mid;
}
}
return -1;
}
状态:完成
一开始使用从两边向中间找的方式险些超时,效率很差劲。
public int[] searchRange(int[] nums, int target) {
int left=0;
int right=nums.length-1;
while(left<=right){
if(nums[left]!=target){
left++;
}
if(nums[right]!=target){
right--;
}
if(right<0||left>nums.length-1) break;
if(nums[right]==target&&nums[left]==target){
return new int[]{left,right};
}
}
return new int[]{-1,-1};
}
然后我先有二分法找到target值,然后向这个值的两端找,效率也不高不过比上面的好
public int[] searchRange(int[] nums, int target) {
if(nums.length==0) return new int[]{-1,-1};
int left=0;
int right=nums.length-1;
int mid=0;
while(left<=right){
mid = left + (right-left)/2;
//先判断一下target是不是nums[left]跟nums[right]
if(target==nums[left]&&target==nums[right]){
mid=target==nums[left]?left:right;
break;
}
//分三种情况 target大于nums[mid],target小于,target等于
if(target>nums[mid]){
left=mid+1;//mid肯定不是target
}else if(target<nums[mid]){
right=mid-1;//mid肯定不是target
}else if(target==nums[mid]){
break;
}
}
if(nums[mid]!=target) return new int[]{-1,-1};
left=mid;
right=mid;
for(int i=1;i<=mid;i++){
if(nums[mid-i]!=target&&nums[mid-i+1]==target){
left=mid-i+1;
break;
}else if(nums[mid-i]==target){
left=mid-i;
}
}
for(int i=1;i<=nums.length-1-mid;i++){
if(nums[mid+i]!=target&&nums[mid+i-1]==target){
right=mid+i-1;
break;
}else if(nums[mid+i]==target){
right=mid+i;
}
}
return new int[]{left,right};
}
然后看了解析发现可以直接用二分法找到两侧的端点这个方法很好,以找左边界为例,使用二分法去查找,如果mid比target小左边则left=mid+1,如果mid等于target则right=mid,就这样不停地移动最后得到的left就是左边的边界点。
状态:完成
因为答案就看前几位,只要把val移到数组末尾就行了。使用两个指针,一个指向答案数组结尾,一个不停地向前移动。当nums[left]不是val时就移动left,left就像个扫地机一样,只要是val他就停下来做交换,把它向后移。
public int removeElement(int[] nums, int val) {
int len=nums.length;
int left=0;
int right=0;
for(right=0;right<nums.length;right++){
int temp=nums[right];
nums[right]=nums[left];
nums[left]=temp;
if(nums[left]!=val) left++;
}
return left;
}