语言
采用的Java语言,一些分析也是用于Java,请注意。
数组理论基础
开源地址
我的认识
数组的特点是在内存空间上连续且数据类型一样。
数组知道下标,get(index)时的时间复杂度为O(1),但并不意味着它寻找某个元素是O(1),而是O(n){不采用一些算法遍历去寻找的话}
正由于数组在内存空间上是连续的,所以必须在增加、删除元素的时候,移动其他元素来保持连续
对于二维数组:
public class Test {
public static void main(String[] args) {
int [] x1 = {1,2,3};
int [][] x2 = {{1, 2, 3}, {3, 4, 5}, {6, 7, 8}, {9,9,9}};
System.out.println(x1.getClass().getName());
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
System.out.println(x2.getClass().getName());
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
System.out.println(x2[0]);
System.out.println(x2[1]);
System.out.println(x2[2]);
System.out.println(x2[3]);
}
}
结果:
[I
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
[[I
[I@378bf509
[I@5fd0d5ae
[I@2d98a335
[I@16b98e56
Java中,数组属于对象,那么可以看到上面代码中x1和x2的类名,就是数组,数组并不是基本数据类型,所以不管是一维数组还是二维数组,都是存在堆中的。
对于每个小数组(每一行),他的内存地址并没有规则,说明二维数组的每一个行的内存地址没有关系
随想录中的解释是这样的:
二分查找
理论
对于二分法,最重要的就是理解两个要点:
1、用二分法的必要条件
对于这个,二分法必须建立在数组中元素是有序且无重复元素的,这个必须保证才能用二分法
2、通过定义区间判断边界
下面围绕第二点做出论述
易错点:
1、while循环中 left < right 还是 <=right
2、
如果nums[mid] > traget ,那么我们应该更新右面的指针,right指针是rigit = middle 还是middle-1
同样,nums[mid]<target,应该更新左面的指针,left指针式 left = middle 还是left = left + 1
解决问题
1、明确区间
在区间搜索的时候,要确定是 [ ) 还是[ ],个人平常就喜欢使用左闭又开,因为这样计算index 的时候,很方便
比如 0 1 2 3 4 5),区间范围是[0,5),那么这6个元素,实际上存在的只有0到4这5个,
那么算长度的话,直接5-0 =5
比如 3 4 5 6 7) 7-3 =4,长度就是 4(3到6这几个数)
2、循环不变量
while循环中,保持对刚开始定义的区间的[] [)确定下来,每次循环都按照左闭右开的去做题,就是循环不变量,坚持后面边界处理的时候,都是左闭右开。
3、两种写法(加上了我自己理解的注释)
public class Test {
public static void main(String[] args) {
int [] x1 = {1,2,3};
System.out.println(binarySearch1(x1, 2));
System.out.println(binarySearch2(x1, 1));
}
/**
* [ ]
* @param arr
*/
public static int binarySearch1(int [] arr,int target){
//[] 右边界要等于最后一位
int left = 0,right = arr.length-1;
//left=right是因为[]的时候,合法,比如[1,1]
while (left<=right){
//主要两个int值相加可能越界的问题
int mid = (left+right)/2;
if(arr[mid]>target){
//左闭右闭,以为arr[mid]已经确定大于target了,所以不能包含这个值,所以right要=mid-1
right = mid - 1;
}else if(arr[mid] < target){
//同上,因为确定不在区间内了,所以也不能包含
left = mid + 1;
}else {
return mid;
}
}
//没找到
return -1;
}
/**
* [ )
*/
public static int binarySearch2(int [] arr,int target){
//【) right指针就可以直接等于length了。!
int left = 0,right = arr.length;
// [1,1) 不合法,所以不加=号
while (left < right){
int mid = (left+right)/2;
if(arr[mid]>target){
// [) arr[mid]大于target,所以可以直接等于,比如 3 大于 2 ,right = 3的话也没事,因为取不到3
right = mid;
}else if(arr[mid] < target){
// 【)左面是开区间,所以确定mid的值不在目标里的话,就必须+1跳过去
left = mid+1;
}else {
return mid;
}
}
return -1;
}
}
复杂度
二分查找复杂度为Logn级别的,做题的时候可以留意
做题
704二分查找
class Solution {
public int search(int[] nums, int target) {
//【) right指针就可以直接等于length了。!
int left = 0,right = nums.length;
// [1,1) 不合法,所以不加=号
while (left < right){
int mid = (left+right)/2;
if(nums[mid]>target){
// [) arr[mid]大于target,所以可以直接等于,比如 3 大于 2 ,right = 3的话也没事,因为取不到3
right = mid;
}else if(nums[mid] < target){
// 【)左面是开区间,所以确定mid的值不在目标里的话,就必须+1跳过去
left = mid+1;
}else {
return mid;
}
}
return -1;
}
}
35.搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为
O(log n)
的算法。
注意排序数组,目标值,logn,可以想到用二分查找
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){
right = mid;
}else if(nums[mid] < target){
left = mid+1;
}else {
return mid;
}
}
// 1 5 3 6 target = 2
// l=0,r=3, m = 1 ,( nums[mid] = 3 ) > target --> r = mid=2;
// l = 0, r = 2 m = 0 (nums[mid]=1) > target -->l = mid+1 = 1;
// l = 1,r = 2. m = 1 -(nums[mid=3 > 2)------>r = mid =1
// l = r = 1 ==插入位置
return left;
}
}
27.移除元素
数组的移除不是简单的删除,因为数组是一个连续的空间,删除一个元素,需要移动后面的元素,保证数组的连续
暴力解法
暴力删除的话,比如123456 删除4 需要先找到4,然后再把后面向前移动
class Solution {
public int removeElement(int[] nums, int val) {
int size = nums.length;
for(int i =0;i<size;i++){
if(nums[i]==val){
for(int j = i+1;j<size;j++){
nums[j-1] = nums[j];
}
size--;
//i--是因为: 1 2 3 4 删除2 此时i=1
// 134 i=1的话,这次循之后外层循环会i++,会错过3,所以需要i--;
i--;
}
}
return size;
}
}
快慢指针
这个也是比较好理解的,快指针遍历,满指针存放新的数组。 理解这里就可以 了
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];
}
}
return slow;
}
}
日后补充
今天作业完成,后续还需要做这些题
随想录34题题解,这里我有些理解不了的地方,群友可以探讨一下。