一.数组理论基础
数组
数组是存放在连续内存空间上的相同类型数据的集合
注意:
1.数组下标都是从0开始的
2.数组的元素不能删,只能覆盖
二维数组
在C++中二维数组在地址空间上是连续的
在java中二维数组的每一行头结点的地址随机,后续结点连续
704.二分查找
https://leetcode.cn/problems/binary-search
注意:1.数组下标从0开始,到nums.length-1结束
2.二分查找要求无重复元素的有序数组
3.“左闭右闭”和“左闭右开”的区别
1.左闭右闭,left和right可相等
[left,right]
①int right = nums.length - 1
②while(left<=right)
③right=mid-1;
class Solution {
public int search(int[] nums, int target) {
while(target < nums[0] || target > nums[nums.length-1])
return -1;
//左闭右闭
int left = 0, right = nums.length - 1;
while(left<=right){
int i=(left+right)/2;
if(nums[i]<target)//target比中间数大
left=i+1;
else if(nums[i]>target)target比中间数小
right=i-1;
else
return i;
}
return -1;
}
}
2.左闭右开,则left和right不可相等
[left,right)
①int right = nums.length
②while(left<right)
③right=mid;
class Solution {
public int search(int[] nums, int target) {
while(target < nums[0] || target > nums[nums.length-1])
return -1;
//左闭右开
int left = 0, right = nums.length ;
while(left<right){
int i=(left+right)/2;
if(nums[i]<target)//target比中间数大
left=i+1;
else if(nums[i]>target)target比中间数小
right=i;
else
return i;
}
return -1;
}
}
35.搜索插入位置
https://leetcode.cn/problems/search-insert-position
注意点:1.时间复杂度要求为O(logn),因此需要使用二分查找
2.在数组中,未找到时,返回left or right+1
3.target不在范围内的情况可以不用考虑
1.左闭右闭
//思路:二分查找,找到则输出下标,找不到则输出left-1
class Solution {
public int searchInsert(int[] nums, int target) {
//target不在范围
if(target <= nums[0])
return 0;
if(target > nums[nums.length -1])
return nums.length;
int left=0,right=nums.length -1;
while(left <= right){
int mid= (left+right)/2;
if(nums[mid]<target)
left=mid+1;
else if(nums[mid]>target)
right=mid-1;
else
return mid;
}
return left;
}
}
2.左闭右开
class Solution {
public int searchInsert(int[] nums, int target) {
int left=0,right=nums.length ;
while(left < right){
int mid= (left+right)/2;
if(nums[mid]<target)
left=mid+1;
else if(nums[mid]>target)
right=mid;
else
return mid;
}
return left;
}
}
27. 移除元素
https://leetcode.cn/problems/remove-element
注意点:1.数组元素不能删除,只能覆盖(循环覆盖,即自带一层循环)
2.数组移除元素=覆盖掉目标元素+数组缩短被移除元素的个数
1.暴力解,两次循环
// 时间复杂度:O(n^2)
// 空间复杂度:O(1)
class Solution {
public 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;
}
}
2.快慢指针法
基础思想(自己根据动图想的):
①快慢指针位置相同时,一起移动,慢指针遇到val即停;
②快指针继续向前,当快慢指针位置不同时,快指针往回覆盖;快指针遇到val时,返回到慢指针位置
进阶思想(根据书上算法分析的):
①仅快指针遍历,当快指针不等于val时,给慢指针赋值
②是“虚拟数组法”的进阶。只不过在“虚拟数组法”中,当指针不等于val时,给另外一个数组赋值,而该算法赋值给同一个数组,从而实现了所谓的“覆盖”
class Solution {
public int removeElement(int[] nums, int val) {
int length =nums.length;
int slowIndex = 0;
for(int fastIndex = 0 ;fastIndex < length;fastIndex++){
if(nums[fastIndex]!=val){//如果快指针位置的值和val不同,快指针给慢指针位置赋值
nums[slowIndex]=nums[fastIndex];
slowIndex++;
}
}
return slowIndex;
}
}
3.相向双指针方法