代码随想录算法训练营第1天 | 数组二分法、数组双指针
二分法
2024年7月3日
重点是理解左闭右开和左闭右闭的选择对middle±1的影响。如果判断过了,下一次循环就不应该包含这个边界。
易错
- 注意计算mid的方式,直接求均值的错误方式会超出上界。
- 不是mid和target比较而是nums[mid]。
题704. 二分查找
//左闭右开
class Solution {
public int search(int[] nums, int target) {
int left=0,right=nums.length;
int mid=0;
while(left<right){
mid = left+(right-left)/2;
if(nums[mid]>target){
right = mid;
}else if(nums[mid]<target){
left = mid+1;
}else{
return mid;
}
}
return -1;
}
}
//左闭右闭
class Solution {
public int search(int[] nums, int target) {
int left = 0,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 -1;
}
}
题35. 搜索插入位置
class Solution {
public int searchInsert(int[] nums, int target) {
int left=0,right=nums.length-1;
int mid=0;
if(target<nums[0]){
return 0;
}
if(target>nums[right]){
return right+1;
}
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. 在排序数组中查找元素的第一个和最后一个位置
class Solution {
public int[] searchRange(int[] nums, int target) {
int left=0,right=nums.length-1;
int mid=0;
int r1=-1,r2=-1;
while(left<=right){
mid = left+(right-left)/2;
if(nums[mid]>target){
right = mid-1;
}else if(nums[mid]<target){
left = mid+1;
}else{
r1=mid;
right=mid-1;//继续往左尝试
}
}
left=0;
right=nums.length-1;
while(left<=right){
mid = left+(right-left)/2;
if(nums[mid]>target){
right = mid-1;
}else if(nums[mid]<target){
left = mid+1;
}else{
r2=mid;
left=mid+1;//继续往右尝试
}
}
return new int[]{r1,r2};
}
}
题69. x 的平方根
class Solution {
public int mySqrt(int x) {
int left=0,right=x;
int mid=0,res=-1;
while(left<=right){
mid = left+(right-left)/2;
if((long)mid*mid<x){//注意必须转long防止int*int溢出
res=mid;
left=mid+1;
}
else if((long)mid*mid>x){
right=mid-1;
}else{
return mid;
}
}
return res;
}
}
题367. 有效的完全平方数
class Solution {
public boolean isPerfectSquare(int x) {
int left=0,right=x;
int mid=0,res=-1;
while(left<=right){
mid = left+(right-left)/2;
if((long)mid*mid<x){//注意必须转long防止int*int溢出
res=mid;
left=mid+1;
}
else if((long)mid*mid>x){
right=mid-1;
}else{
return true;
}
}
return false;
}
}
移除数组元素
使用快慢指针。快指针遍历,遇到符合需求的,用慢指针给数组赋值。
注意
- 遍历范围为快指针直到数组末尾;
- 不管是不是同一位置,统一将快指针数值复制到慢指针;
- 如果不符合要求,慢指针不动,快指针进1;
- 如果符合要求,先复制值,再统一进1。
题27. 移除元素
class Solution {
public int removeElement(int[] nums, int val) {
int left=0,right=0;
for(;right<nums.length;){
if(nums[right]!=val){
nums[left] = nums[right];
left+=1;//赋了有效值才右移
}
right+=1;//每一次都右移
}
return left;
}
}
题26. 删除排序数组中的重复项
class Solution {
public int removeDuplicates(int[] nums) {
HashSet<Integer> set1 = new HashSet<>();
int r1 = 0,r2=0;
for(;r2<nums.length;){
if(!set1.contains(nums[r2])){
set1.add(nums[r2]);
nums[r1] = nums[r2];
r1+=1;
}
r2+=1;
}
return set1.size();
}
}