一、理论基础
1、数组的元素是不能删的,只能覆盖。
2、array[2][3]只有有3*4=12个元素
3、C++二维数组的初始化
int a[3][4] = {
{0, 1, 2, 3}, /* 初始化索引号为 0 的行 */
{4, 5, 6, 7}, /* 初始化索引号为 1 的行 */
{8, 9, 10,11} /* 初始化索引号为 2 的行 */
};
内部嵌套的括号是可选的,下面的初始化与上面是等同的:
int a[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
所以是按行分割
4、C++中二维数组在地址空间上是连续的,每两个地址差4,正好是个int的大小
5、java中二维数组不连续,可能为以下这样
二、二分查找
前提条件:数组有序,无重复元素,你必须设计并实现时间复杂度为O(log n) 的算法解决此问题
核心思想:假定target在【left,right】区间,用mid更新区间边界
错误提示:
1判断条件是数组元素nums【mid】,不是下标mid
2对于target超出数组边界的地方要约束,不然会超时
3mid要在循环内,不然无法更新
class Solution {
public int search(int[] nums, int target) {
intleft = 0, right = 0, mid = 0;
intn = nums.length;
right = n - 1;
if (target < nums[0] || target > nums[n - 1])
{
return -1;
}
while (left
{
mid = (left +right) / 2;
if (nums[mid] == target)
{
return mid;
}
else if(target
{
right = mid - 1;
}
else
{
left = mid + 1;
}
}
return -1;
}
}
提升1 搜索插入位置
前提条件:
核心思想:每次区间内只剩2个元素的时候,left就是要插入的地方了
错误提示:
1超出数组边界的地方都写成了nums【left】
2mid= (left + right)/ 2,因为3/2=1.5=1
class Solution {
public int searchInsert(int[] nums, int target) {
intleft = 0;
intposition = 0;
intn = nums.length;
intright = n -1;
if (target < nums[left])
{
position = 0;
return position;
}
if (target > nums[right])
{
position = right+ 1;
return position;
}
while (left
{
int mid = (right + left) / 2 ;
if (nums[mid] == target)
{
return mid;
}
else if (nums[mid] >target)
{
right = mid - 1;
}
else
{
left = mid + 1;
}
}
return left;
}
}
提升2 在排序数组中查找元素的第一个和最后一个
前提条件:
核心思想:每次区间内只剩2个元素的时候,left就是要插入的地方了
错误提示:
1在数组内讨论时未注意约束数组越界问题
2返回类型必须遵从
3线性查找时间复杂度逼近O(logn)
4起始位置和结束位置分别开始二分查找
线性查找(超时):
class Solution {
public int[] searchRange(int[] nums, int target) {
//finalint LENGTH = 100000;
intleft = 0;
intmid = 0;
intpositionLeft= 0;
intpositionRight= 0;
intmoveFlag = 0;
//int[][]res = new int[LENGTH][LENGTH];
intn = nums.length;
intright = n -1;
//超出数组上下界
if (target> nums[n - 1] || target < nums[0])//是或不是且
{
int[] res1 = {-1, -1};
return res1;
}
else
{
//数组内的情况
while (left
{
mid= (right + left) / 2;
if (target == nums[mid])
{
moveFlag = mid;
//看它下一个是否也是target
moveFlag++;
while (target == nums[moveFlag] &&moveFlag 1)//注意约束条件
{
positionRight = moveFlag;
moveFlag++;
}
//看它上一个是否也是target
moveFlag = mid - 1;
while (target == nums[moveFlag] &&moveFlag >= 0)//注意约束条件
{
positionLeft = moveFlag;
moveFlag--;
}
}
else if (target >nums[mid])
{
left = mid + 1;
}
else
{
right = mid - 1;
}
}
int[] res2 = {positionLeft,positionRight};
return res2;
}
}
}
二分查找(通过):
查找起始位置:首先,使用二分查找找到目标元素的起始位置。在二分查找中,当找到目标元素时,不要立即返回,而是继续向左(更小的索引方向)搜索,直到找到起始位置。
查找结束位置:接下来,使用二分查找找到目标元素的结束位置。在二分查找中,当找到目标元素时,不要立即返回,而是继续向右(更大的索引方向)搜索,直到找到结束位置。
class Solution {
public int[] searchRange(int[] nums, int target) {
intleft = 0;
intn = nums.length;
intright = n -1;
intpositionLeft= getPositionLeft(nums, target);
intpositionRight= getPositionRight(nums, target);
if (n == 0)
{
return new int[]{-1,-1};//数组的写法
}
//超出数组上下界
if (target> nums[right] || target < nums[0])//是或不是且
{
int[] res1 = {-1, -1};
return res1;
}
//在数组内
else
{
//在数组范围内却没有找到
if (positionLeft == -2 ||positionRight == -2)//return后面不可以加句子
{
int[] res1 = {-1, -1};
return res1;
}
else
{
int[] res2 = {positionLeft,positionRight};
return res2;
}
}
}
//左边界
int getPositionLeft(int[] nums, int target){
intleft = 0;
int mid = 0; //mid使用之前要定义
intn = nums.length;
intright = n -1;
intpositionLeft= -2;
while (left
{
mid = (left +right) / 2;
if (nums[mid] == target)
{
positionLeft = mid;
right = mid - 1;
}
else if (nums[mid] >target)
{
right = mid - 1;
}
else
{
left = mid + 1;
}
}
return positionLeft;
}
//右边界
int getPositionRight(int[] nums, int target) {
intleft = 0;
intmid = 0;
intn = nums.length;
intright = n -1;
intpositionRight= -2;
while (left
{
mid = (left +right) / 2;
if (nums[mid] == target)
{
positionRight = mid;
left = mid + 1;
}
else if (nums[mid]
{
left = mid + 1;
}
else
{
right = mid - 1;
}
}
return positionRight;
}
}
提升3 x的平方根
前提条件:
核心思想:二分查找存在的意义就是简化顺序查找
错误提示:
1在 square < x 的情况下,更新 res 为 mid,以便在没有找到完全匹配的情况下,返回最接近的整数平方根。
2mid溢出了,是最大的问题。最后用long解决,但是返回值要是int。
class Solution {
publicint mySqrt(int x) {
//存在的意义就是简化顺序查找
longleft = 0;
longright = x;
long mid = 0;//int是32位
intres = 0;
long flag = 0;//两个int相乘
//mid=right/2;
while (left
{
mid = left +(right - left) / 2;
flag = mid * mid;
if (flag == x)
{
res= (int)mid;
//System.out.println(res);
return res;
}
else if (flag > x)//不合格的状态
{
right = mid - 1;
}
else//这个情况也要返回因为如果找不到恰好的,就找接近的。
{
res= (int)mid;
left = mid + 1;
}
}
return res;
}
}
提升4 有效的完全平方数
前提条件:
比上一题简单一点,因为只有平方恰好=target,才是唯一的可行情况,没有近似的这个想法。
错误提示:
1squre忘记放进循环了。
2比较条件的时候需要把int强制类型转化成long,不然会无脑判fasle的。
class Solution {
public boolean isPerfectSquare(int num) {
int left = 0;
int right = num;
long mid = 0;
while (left <= right)
{
mid = left + (right - left) / 2;
long square = mid * mid;
if (square == (long)num)
{
return true;
}
else if (square > (long)num)
{
right = (int)mid - 1;
}
else
{
left = (int)mid + 1;
}
}
return false;
}
}