704.二分查找
文章链接: 代码随想录
这道题目是二分查找思想。 主要是代码要写的简洁,不冗余。 注意要点:
1.对于左闭右闭区间,和左闭右开区间2种方式, 考虑边界问题。
左闭右闭区间时候,更新left或者right,都是+1,或者-1,直接考虑边界。
代码如下:
class Solution {
public int search(int[] nums, int target) {
int left=0;
int right =nums.length-1;
while(left<=right){
int middle = left+(right-left)/2;
if(target== nums[middle]){
return middle;
}else if( target >nums[middle]){
left =middle+1;
}else{
right =middle-1;
}
}
//这个条件下不满足,就是没有找到目标
return -1 ;
}
}
左闭右开区间时候,更新left时候,仍然是+1,但是更新right,不能-1,因为我们的逻辑是 [left ,right),并且 我们定义int right =nums.length,不能-1
代码如下:
class Solution {
public int search(int[] nums, int target) {
int left=0;
int right =nums.length;
while(left<right){
int middle = left+(right-left)/2;
if(target== nums[middle]){
return middle;
}else if( target >nums[middle]){
left =middle+1;
}else{
right =middle;
}
}
//这个条件下不满足,就是没有找到目标
return -1 ;
}
}
2.考虑代码的简洁性,不能把middle 的更新放到多个if else判断分支中去。
只需要在while 循环体开始定义就行。
如下冗余:
class Solution {
public int search(int[] nums, int target) {
int left=0;
int right =nums.length;
int middle = left+(right-left)/2;
while(left<right){
if(target== nums[middle]){
return middle;
}else if( target >nums[middle]){
left =middle+1;
middle = left+(right-left)/2;
}else{
right =middle;
middle = left+(right-left)/2;
}
}
//这个条件下不满足,就是没有找到目标
return -1 ;
}
}
35.搜索插入位置
这里考虑的是left>right,当循环结束后, left指向的元素始终是大于等于target的候选位置,这是target应该插入的位置
right指向的元素始终小于target 。
class Solution {
public int searchInsert(int[] nums, int target) {
int left =0;
int right = nums.length-1;
while(left<=right){
int middle =left+(right-left)/2;
if(nums[middle] ==target){
return middle;
}else if (nums[middle]>target){
right =middle-1 ;
}else {
left =middle +1 ;
}
}
return left;
}
}
34. 在排序数组中查找元素的第一个和最后一个位置
这道题目的方法和二分查找差不多,重要的是返回多个目标值,需要多一步循环迭代,找到目标值的起点和终点, 用while循环迭代便可。 代码如下:
class Solution {
public int[] searchRange(int[] nums, int target) {
int [] dos = new int []{-1,-1};
if (nums.length == 0 || target < nums[0] || target > nums[nums.length - 1]) {
return dos;
}
int left =0;
int right =nums.length-1;
while (left <= right){
int middle = left + ((right - left) >> 1);
if (target >nums[middle]){
left =middle +1;
}else if (target <nums[middle]){
right =middle -1;
}else{
int start=middle ;
while(start >0 && nums[start-1]==target ){
start--;
}
int end =middle ;
while (end <nums.length-1 &&target ==nums[middle] && nums[end+1]==target ){
end++;
}
dos[0]=start;
dos[1]=end;
return dos;
}
}
return dos;
}
}
27.移除元素
如果用暴力解法的话, 就是从nums数组中找到第一个属于val的位置,nums[i] =val ; 然后对i+1 的位置以及之后的数据进行前移动:
class Solution {
public static int removeElement(int[] nums , int val ){
int length = nums.length;
for(int i=0 ;i<length;i++){
if(nums[i]==val){
for(int j=i+1;j<length;j++){
nums[j-1]=nums[j];
}
i--;
length--;
}
}
return length;
}
}
这道题用双指针的方式去写。 其中最重要的是要理解fast指针寻找新数组的数,不属于新数组的数,就会自动跳过。 slow指针是记录新数组的下标,所以slow是一步步迭代。 这样就能做到把fast找到的的值逐个放到slow迭代次序的数组中去。 完成非目标val数据的向前移动和覆盖,实现删除元素的目的。
class Solution {
public int removeElement(int[] nums, int val) {
int slow =0;
for(int fast =0; fast<nums.length; fast++){
if(nums[fast] != val){
nums[slow]=nums[fast];
slow++;
}
}
return slow;
}
}
977.有序数组的平方
这道题的得排大小, 注意原始数组是非降序排序,所以它的最大值一定是左侧或者右侧。 那么我们设定一个新的数组,往里面填充值。首先拿最左侧和最右侧的值(经过平方后的值)来比较,最大的放在新数组的最后一个位置,并且把新数组的索引位置向前移动一个。
同时要判断到底是左侧大的,or右侧大的,如果是左侧大的,left++,移动左侧, 反之,移动right--
class Solution {
public int[] sortedSquares(int[] nums) {
int [] result =new int [nums.length];
int pos = nums.length-1;
int left =0 ;
int right =nums.length-1;
while(left<=right){
if(nums[left]*nums[left]> nums[right]*nums[right]){
result[pos] =nums[left]*nums[left];
left++;
}else{
result[pos]=nums[right]*nums[right];
right--;
}
pos--;
}
return result;
}
}