1.数组理论基础
文档讲解: 代码随想录
1.数组是存放在连续内存空间上的相同类型数据的集合(下标都是从0开始的)
2.删除或者增添元素的时候,需要考虑其他元素的地址,而且数组的元素不能删,只能覆盖
3.在C++中,二维数组在内存的空间地址是连续的,而JAVA并不是
2.704.二分查找
class Solution {
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length; //左闭右开
while(left < right){
int mid = left + (right - left) / 2;
if(target > nums[mid]){
left = mid + 1;
}
else if(target < nums[mid]){
right = mid;
}
else {
return mid;
}
}
return -1;
}
}
这道题前段时间刚刚刷过,所以很容易的就写出来了。在写while循环的时候犹豫了一下,由于左闭右开,所以left无法等于right,因此确定为小于号。在写完左闭右开后,再写一下左闭右闭。
二分法的前提条件:(1)数组为有序数组(2)数组中无重复元素
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;
}
else if(target < nums[mid]){
right = mid - 1;
}
else {
return mid;
}
}
return -1;
}
}
扩展题
35.搜索插入位置
class Solution {
public int searchInsert(int[] nums, int target) {
int left = 0;
int right = nums.length;//左闭右开
while(left < right){
int mid = left + (right - left) / 2;
if(target > nums[mid]){
//target在右边
left = mid + 1;
}
else if(target < nums[mid]){
right = mid;
}
else {
return mid;
}
}
return left;
}
我对比了和代码随想录给出的答案,在未在数组中找到target的情况下,我是通过举例得到left,而答案是从逻辑上确认为right,结束while循环时left=right。复盘一下答案的逻辑:
(1)target出现在所有元素之前[0,0)
(2)target在数组中,return mid
(3)target不在数组中,但取值范围在[left,right)
(4)target出现在所有元素之后[left,right)
结合所有情况,左闭右开,应该是取不到的right
34.在排序数组中查找元素的第一个和最后一个位置
class Solution {
public int[] searchRange(int[] nums, int target) {
int left = searchLeft(nums,target);
int right = searchRight(nums,target);
if(left == -2 || right == -2){
return new int[] {-1,-1};
}
else if(right - left >= 2){
return new int[] {left + 1,right - 1};//target==nums[mid]的时候更新边界
}
else return new int[] {-1,-1};
}
int searchLeft(int[] nums, int target){
int left = 0;
int right = nums.length - 1;//左闭右闭
int leftBorder = -2;//记录leftBorder未被赋值的情况
while(left <= right){
//不应该搜索target在数组的位置,而应该不断用区间去逼近target
int mid =left + (right - left) / 2;
if(target <= nums[mid]){
right = mid - 1;
leftBorder = right;
}
else{
left = mid + 1;
}
}
return leftBorder;
}
int searchRight(int[] nums, int target){
int left = 0;
int right = nums.length - 1;//左闭右闭
int rightBorder = -2;//记录rightBorder未被赋值的情况
while(left <= right){
//不应该搜索target在数组的位置,而应该不断用区间去逼近target
int mid =left + (right - left) / 2;
if(target >= nums[mid]){
left = mid + 1;
rightBorder = left;
}
else{
right = mid - 1;
}
}
return rightBorder;
}
}
3.27.移除元素
暴力解法:
class Solution {
public int removeElement(int[] nums, int val) {
int length = nums.length;
for(int i = 0; i < nums.length; i++){
if(nums[i] == val){
length--;
for(int j = i; j < nums.length - 1; j++){
nums[j] = nums[j + 1];
}
i--;
}
}
return length;
}
}
很奇怪,这样子跑的时间好长,思路应该是没错的。
双指针法:
class Solution {
public int removeElement(int[] nums, int val) {
int j = 0;
for(int i = 0; i < nums.length; i++){
if(nums[i] != val){
nums[j++] = nums[i];//不为0的保留
}
}
return j;//在循环中j最后会在赋值后执行+1
}
}
这道题也是不久前刷过,双指针的思路没什么问题,但是在return j 的时候出错了,忘记了在循环中 j 会在赋值后自加1。
扩展题
26.删除有序数组中的重复项
题目链接:26
class Solution {
public int removeDuplicates(int[] nums) {
int len = 1;
int val = nums[0];
for(int i = 1; i < nums.length; i++){
if(nums[i] != val){
nums[len++] = nums[i];
val = nums[i];
}
}
return len;
}
}