(一)数组理论基础
新学到的:
1. 不同编程语言的内存管理不同。比如,在C++中二维数组是连续分布的;Java没有指针,也不对程序员暴露其元素的地址,寻址操作完全交给虚拟机,所以看不到每个元素的地址情况。
(二)704.二分查找
复习
要点:
1. 在循环中始终坚持根据查找区间的定义来做边界处理。区间的定义:不变量。
思路:
1. left=0,right = nums.length-1;mid= left+(right-left)/2;
2. 【左闭右闭】:[left, mid-1], [mid], [mid+1, right];
3. 【左闭右闭】判断target和nums[mid]大小
(1)target == nums[mid],返回mid;
(2)target<nums[mid],right = mid-1(只要left<=right),更新mid,重新判断;
(3)target>nums[mid],left = mid+1(只要left<=right),更新mid,重新判断;
3. left>right时,结束while循环,返回-1。
需注意的代码细节:
1. 判断大小关系时:if( ){ } else if( ) { } else { }(即,其中一个判断条件可省略)。
2. 【左闭右闭】循环判断条件:left<=right。因为 left = right 时数组有元素。
3. 【左闭右闭】更新left/right:必满足 target != nums[mid],因此left = mid-1, right = mid+1。
4. target < nums[left] 和 target > nums[right] 的情况,可以不用单独判断。while循环完成后直接return -1即可。
//【左闭右闭】
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 (nums[mid] > target){
right = mid -1;
} else if (nums[mid] < target){
left = mid + 1;
} else {
return mid;
}
}
return -1;
}
};
其他思路:
1. 【左闭右开】:[left, mid), [mid], [mid+1, right)
(1)right = nums.length
(2)循环条件为 left<right
(3)更新right时,right = mid
//【左闭右开】
class Solution {
public int search(int[] nums, int target){
int left = 0;
int right = nums.length;//[left, right)
while (left < right){//不同之处
int mid = left + (right - left)/2;
if (nums[mid] > target) {
right = mid;//不同之处
} else if (nums[mid] < target) {
left = mid + 1;
} else {
return mid;
}
}
return -1;
}
};
(三)27. 移除元素
复习
思路:
【相向双指针法】(最终使所有val值元素在数组右侧)
1. l = 0, r = nums.length-1;
2. 当满足l <= r 时,l 向右移动,直至 nums[l] == val ;r 向左移动,直至 nums[r] != val。此时若满足 l < r ,则交换 l 和 r 所指元素的值。若不满足,直接break。
2. 结束循环后,l 一定指向数组从左往右第一个val值元素。输出 l 。
需注意的代码细节:
1. l 和 r 在移动中,仍要满足 l <= r(注意指针循环条件);
2. 不需要声明 size 另外记录非 val 元素的个数。最后直接 return l 即可。
class Solution {
public int removeElement(int[] nums, int val) {
int l,r;
for(l = 0, r = nums.length-1; l<=r;){
while(l<=r && nums[l] != val){//移动中仍要满足 l <= r
l++;
}
while(l<=r && nums[r] == val){//移动中仍要满足 l <= r
r--;
}
if(l>r){
break;
}
nums[l] = nums[r];
nums[r] = val;
}
return l;
}
}
其他思路:双指针法(快慢指针法)
【 fast 遍历判断原数组元素是否需要移除,slow 构建新数组(覆盖原数组)。slow 和 fast 最终所差步数即为原数组中 val 值元素个数】
1. 指针 slow 和 fast 同时从第一个元素出发。
2. 若 fast 所指为非 val 值元素,更新 slow 所指元素的值为 fast 所指元素的值,两指针继续一起移动;若 fast 所指为 val 值元素,slow 停,fast 继续移动。
//【快慢指针】
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;
}
}