目录
数组
数组是存放在连续内存空间上的相同类型数据的集合。
数组可以方便的通过下标索引的方式获取到下标下对应的数据。
举一个字符数组的例子
数组的优缺点
(1)优点
数组根据索引查询一个数据的时间复杂度为O(1) 数组首地址+索引*数据类型偏移量
(2)缺点
正是因为数组的在内存空间的地址是连续的,所以我们在删除或者增添元素的时候,就难免要移动其他元素的地址时间复杂度为O(n)。
例如删除下标为3的元素,需要对下标为3的元素后面的所有元素都要做移动操作,如图所示:
数组之二分
1.二分的条件
有序数组 无重复元素
2.二分的循环结束条件及左右端点的改变
二分查找涉及的很多的边界条件,逻辑比较简单,但就是写不好。例如到底是 while(left < right)
还是 while(left <= right)
,到底是right = middle
呢,还是要right = middle - 1
呢?
我们定义 target 是在一个在左闭右闭的区间里,也就是[left, right] (这个很重要非常重要)。
例如在数组:1,2,3,4,7,9,10中查找元素2
【1】确定搜索范围 left=0 right=arr.length-1 [left,right]
【2】比较中间值 mid=(left+right)/2 如果中间值大于target那么target就在左半部分 如果中间值小于target那么target就在右半不放呢
【3】更新搜索范围 这个时候就要看 如果在左半部分 肯定是要改变right
疑难点: right=mid-1 还是right=mid ?
if (nums[middle] > target) right 要赋值为 middle - 1,因为当前这个nums[middle]一定不是target(也就是说target一定不能在mid位置)那么搜索范围肯定不,那么接下来要查找的左区间结束下标位置就是 middle - 1 类比 如果中间值大于target left=mid+1
[4]循环【1-3】
3.常规二分示例
class Solution {
public int search(int[] nums, int target) {
int left =0;
int right=nums.length-1;
int mid=0;
while(left<=right){
mid=(left+right)/2;
int num=nums[mid];
if(num>target){
right=mid-1;
}else if(num<target){
left=mid+1;
}else {
return mid;
}
}
return -1;
}
}
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int t = sc.nextInt();
for (int i = 0; i < t; i++) {
//【1】确定取值范围
double a = 0.0;
double b = 100.0;
double y = sc.nextDouble();
if (y>201805052114.0||y<14.0) {
System.out.println(-1);
} else {
double mid = 0;
while (b-a>0.00001) {
mid = (a + b) / 2;
//比较中间值与目标值
if (2018*mid*mid*mid*mid+21*mid+5*mid*mid*mid+5*mid*mid+14>y) {//
b = mid;//更新搜索范围
} else {
a=mid;//更新搜索范围
}
}
System.out.printf("%.4f\n", mid);
}
}
}
}
class Solution {
public int searchInsert(int[] nums, int target) {
int left=0;
int right=nums.length-1;
int mid=0;
while(left<=right){
mid=(left+right)>>1;
if(nums[mid]>target){//比较中间值
right=mid-1;
}else if(nums[mid]<target){
left=mid+1;
}else{
return mid;
}
}
return left;
}
}
4.有重复元素的二分
class Solution {
public int[] searchRange(int[] nums, int target) {
int left=0;
int right=nums.length-1;
int mid=0;
int index=0;
while(left<=right){
mid=(left+right)/2;
int num=nums[mid];
if(num>target){
right=mid-1;
}else if(num<target){
left=mid+1;
}else {
index=mid;
break;
}
}
if(left>right){
int[]arr={-1,-1};
return arr;
}else
{
int start=index;
int end=index;
while(--start>=0&&start<nums.length&&nums[start]==target);
while(++end>=0&&end<nums.length&&nums[end]==target);
int arr[]={start+1,end-1};
return arr;
}
}
}