一,对数组的新认识
不同编程语言的内存管理是不一样的,以C++为例,在C++中二维数组是连续分布的。而对于Java来说,二维数组不是连续分布的。
思考:
cout << &array[0][0] << " " << &array[0][1] << " " << &array[0][2] << endl;
对C++来说,可以通过取址运算符来获取二维数组的具体的地址值,那么Java如何获取array[0][1]的地址呢?
二,704.二分查找
二分查找也叫做折半查找 ,元素必须是有序的,从小到大,或者从大到小都是可以的。
用给定值先与中间结点比较。比较完之后有三种情况:
-
相等
说明找到了
-
要查找的数据比中间节点小
说明要查找的数字在中间节点左边
-
要查找的数据比中间节点大
说明要查找的数字在中间节点右边
题目来源:力扣
对于左闭右闭区间,代码如下
class Solution {
public int search(int[] nums, int target) {
int left=0;
int right=nums.length-1;
while(left<=right)
{
int mid=left+(right-left)/2;
if(target>nums[mid])
left=mid+1;
if(target<nums[mid])
right=mid-1;
if(target==nums[mid])
return mid;
}
return -1;
}
}
遇到的问题:
对于左闭右开的代码写不出来,不太理解
对于左闭右开区间,代码如下
class Solution {
public int search(int[] nums, int target) {
int left=0;
int right=nums.length;
while(left<right)
{
int mid=left+((right-left)>>1);
if(target>nums[mid])
left=mid+1;
else if(target<nums[mid])
right=mid;
else
return mid;
}
return -1;
}
}
左闭右开和左闭右闭区间对比(三处不同)
左闭右闭
int right=nums.length-1;
while(left<=right)right=mid-1;
左闭右开
int right=nums.length;
while(left<right)
right=mid;
同时,代码中舍弃了
mid=(left+right)/2的用法,采用
int mid=left+((right-left)>>1);
int mid=left+((right-left)/2);
两者都是为了防止溢出,相关文章和其他方法:
看完微软大神写的求平均值代码,我意识到自己还是too young了
int mid=left/2+right/2+(left&right&1);
int mid=(left&right)+(left^right)/2;
在while循环前,可以加上如下句子:防止多次循环运算
// 避免当 target 小于nums[0] nums[nums.length - 1]时多次循环运算
if (target < nums[0] || target > nums[nums.length - 1]) {
return -1;
}
三,27.移除元素
1.暴力解法代码:时间复杂度O(
),空间复杂度O(n)
数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖。
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];
}
i--;
size --;
}
}
return size;
}
}
对于边界情况,也是可以改一下的:
for(int j=i+1;j<size;j++)
{
nums[j-1]=nums[j];
}
可改为:
for(int j=i;j<size-1;j++)
{
nums[j]=nums[j+1];
}
2.快慢双指针法:
指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。
定义快慢指针
- 快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
- 慢指针:指向更新 新数组下标的位置
class Solution {
public int removeElement(int[] nums, int val) {
int fast=0;
int slow=0;
for(fast=0;fast<nums.length;fast++)
{
if(val!=nums[fast])
{
nums[slow]=nums[fast];
slow++;
}
}
return slow;
}
}
nums[slow]=nums[fast];
slow++;
也可一步到位:
nums[slow++]=nums[fast];
同时注意,是直接返回slow,而不是slow+1;

双向双指针法:
class Solution {
public int removeElement(int[] nums, int val) {
int left=0;
int right=nums.length-1;
while(right>=0&&nums[right]==val) right--;
while(left<=right)
{
if(nums[left]==val)
{
nums[left]=nums[right];
right--;
}
left++;
while(right>=0&&nums[right]==val) right--;
}
return left;
}
}
while(right>=0&&nums[right]==val) right--;
其中的right>=0不能改为right>0;否则只有一个元素时候会输出空值
