数组思维导图总结:
有序数组才可用二分法
解决此题目需注意搜索区间,如数组的左闭右闭区间和左闭右开区间对应的搜索区间是不同的。
题目1:704. 二分查找
class Solution {
public int search(int[] nums, int target) {
int left=0;
int right=nums.length-1;
//如果是左闭右闭区间
while(left<=right){
int middle=(left+right)/2;
//二分法就是比较middle的值是否大于、小于、等于target
if(nums[middle]>target){
//搜索区间变动 此时middle已经比较过了因为是左闭右闭区间
right=middle-1;
}else if(nums[middle]<target){
left=middle+1;
}else{
return middle;
}
}
return -1;
}
}
题目2:35. 搜索插入位置
注意:卡在返回值了right+1了,二刷需注意这四种情况,把right+1换成left也可,因为left<=right的循环到最后一次会符合nums[middle]<target条件将left进行+1,所以left就是元素要插入的位置
class Solution {
public int searchInsert(int[] nums, int target) {
int left=0;
int right=nums.length-1;
while(left<=right){
int middle=(left+right)/2;
if(nums[middle]>target){
right=middle-1;
}else if(nums[middle]<target){
left=middle+1;
}else{
return middle;
}
}
// 分别处理如下四种情况
// 目标值在数组所有元素之前 [0, -1] -1不返回
// 目标值等于数组中某一个元素 return middle;
// 目标值插入数组中的位置 [left, right],return right + 1/left
// 目标值在数组所有元素之后的情况 [left, right], 因为是右闭区间,所以 return right + 1/left
return right+1;
}
}
题目3: 34. 在排序数组中查找元素的第一个和最后一个位置
思路:通过二分法找到target值,通过循环找到最左侧和最右侧的值
注意:当找到target值时,要通过便历找到最左侧和最右侧的值,二刷时需注意
class Solution {
public int[] searchRange(int[] nums, int target) {
if(nums.length==0){
return new int[]{-1,-1};
}
int left = 0;
int right = nums.length-1;
while(left<=right){
int middle=(left+right)/2;
if(nums[middle]>target){
right=middle-1;
}else if(nums[middle]<target){
left=middle+1;
}else {
int middleLeft=middle;
int middleRight=middle;
//边界条件容易出错
while(middleLeft-1>=0&&nums[middle]==nums[middleLeft-1]){
middleLeft--;
}
//边界条件容易出错
while(middleRight+1<nums.length &&nums[middle]==nums[middleRight+1]){
middleRight++;
}
return new int[]{middleLeft,middleRight};
}
}
return new int[]{-1,-1};
}
}
题目4: 27. 移除元素
1)暴力解法 时间复杂度:O(n^2) 空间复杂度:O(1)
注意:忘记将下标和数组最右侧下标缩减导致没ac
class Solution {
public int removeElement(int[] nums, int val) {
int size=nums.length;
for(int i=0;i<=size-1;i++){
if(nums[i]==val){
for(int j=i;j<size-1;j++){
nums[j]=nums[j+1];
}
//因为下标i以后的数值都向前移动了一位,所以i也向前移动一位
i--;
//数组也缩减一位
size--;
}
}
return size;
}
}
2)双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。慢指针指的是新数组中的值。时间复杂度:O(n) 空间复杂度:O(1)
注意:完全没get到这个点,看了视频才理解慢指针是指新数组中的值,所以当快指针不等于目标值时要更新新数组
class Solution {
public int removeElement(int[] nums, int val) {
//新数组中的下标
int show=0;
for(int fast=0;fast<nums.length;fast++){
//当快指针不等于目标值时,将快指针的值赋值给新数组
if(nums[fast]!=val){
nums[show]=nums[fast];
show++;
}
}
return show;
}
}
题目5: 977.有序数组的平方
1)暴力解法 时间复杂度:O(n + nlogn)
class Solution {
public int[] sortedSquares(int[] nums) {
//平方
for(int i=0;i<nums.length;i++){
nums[i]=nums[i] * nums[i];
}
//排序
Arrays.sort(nums);
return nums;
}
}
2)双指针法
注意:创建新数组 因为边界问题没ac
class Solution {
public int[] sortedSquares(int[] nums) {
int left=0;
int right=nums.length-1;
int[] result=new int[nums.length];
int k=result.length-1;
while(left<=right){
if(nums[right] * nums[right]>nums[left] * nums[left]){
result[k]=nums[right] * nums[right];
right--;
k--;
}else{
result[k]=nums[left] * nums[left];
left++;
k--;
}
}
return result;
}
}
题目6:209.长度最小的子数组
1)暴力解法:在暴力解法中,是一个for循环滑动窗口的起始位置,一个for循环为滑动窗口的终止位置,用两个for循环 完成了一个不断搜索区间的过程 。时间复杂度:O(n^2)
注意:子序列长度为end-start+1,每次收集子序列要把sum置为0
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int result=Integer.MAX_VALUE;
//start为子序列的起始位置
for(int start=0;start<nums.length;start++){
int sum = 0;
//end为子序列的终止位置
for(int end=start;end<nums.length;end++){
sum+=nums[end];
if(sum>=target){
result= Math.min(end-start+1,result);
break;
}
}
}
return result==Integer.MAX_VALUE?0:result;
}
}
2)滑动窗口:如何用一个for循环来解决问题。
注意:如果用一个for循环索引应表示终止位置。
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int result=Integer.MAX_VALUE;
//start为子序列的起始位置
int start=0;
int sum = 0;
//end为子序列的终止位置
for(int end=start;end<nums.length;end++){
sum+=nums[end];
//用while是为了防止给定数组中每一个子序列的和都大于target的情况,一直取到最小的子序列
while(sum>=target){
result= Math.min(end-start+1,result);
//起始位置做变动
sum-=nums[start];
start++;
}
}
return result==Integer.MAX_VALUE?0:result;
}
}
题目7:59. 螺旋矩阵 II
注意:模拟转圈循环遍历上右下左的下标位置,转圈到最后剩一个值的时候(判断为奇数的时候)直接赋值就好了
class Solution {
public int[][] generateMatrix(int n) {
//二维数组
int[][] res = new int[n][n];
//控制循环次数
int size=0;
//startX ,startY表示每一圈的起始位置 要跟着变动
int startX=0;
int startY=0;
//index表示每一圈要缩减的最后位置
int index=1;
//count表示转圈的每一个数
int count=1;
int x,y;
//转n/2圈
while(size++<n/2){
//区间为左闭右开
//上层
for(y=startY;y<n-index;y++){
res[startX][y]=count++;
}
//右层
for(x=startX;x<n-index;x++){
res[x][y]=count++;
}
//下层
for(;y>startY;y--){
res[x][y]=count++;
}
//左层
for(;x>startX;x--){
res[x][y]=count++;
}
//下一圈
startX++;
startY++;
index++;
}
if (n % 2 == 1) {
res[startX][startY] = count;
}
return res;
}
}