代码随想录算法训练营第一天 | 704.二分查找,27.移除元素 ,977.有序数组的平方
704.二分查找
给定一个 n
个元素有序的(升序)整型数组 nums
和一个目标值 target
,写一个函数搜索 nums
中的 target
,如果目标值存在返回下标,否则返回 -1
。
示例 1:
输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4
示例 2:
输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1
1.左闭右闭
- 明确区间为[left,right]。那么当while循环的时候就要判断left<=right是否有意义,当区间为[1,1]时,1<=1在区间范围内是有意义的(若是左闭右开[1,1),很明显右侧的1不包含在区间内部,所以1<=1是没有意义的);
- 当更新区间的时候if(nums[middle]>target)时,应该更新right,并且由于区间是闭的,很明确nums[middle]不在更新的区间内,所以right=middle-1;
- 当更新区间的时候if(nums[middle]<target)时,应该更新left,并且由于区间是闭的,很明确nums[middel]不在更新的区间内,所以left=middle+1。
class Solution {
//左闭右闭
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length-1;
if(target < nums[left] || target > nums[right]){
return -1;
}
while(left <= right){
int middle = (left + right)/2;
if(target > nums[middle]){
left = middle + 1;
}else if(target < nums[middle]){
right = middle - 1;
}else{
return middle;
}
}
return -1;
}
}
2.左闭右开
- 明确区间为[left,right)。当while循环的时候就要判断left<=right是否有意义,这里无意义,所以应当是left<right;
- 当更新区间的时候,if(nums[middle]>target),由于右开,本身right的值不在判断范围内,而nums[middle]也不在更新的区间内,所以right=middle;
- if(nums[middle]<target),由于左闭,而nums[middle]本身不在更新的区间内,所以left=middle+1。
class Solution {
//左闭右开
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length;
if(target < nums[left] || target > nums[right-1]){
return -1;
}
while(left < right){
int middle = (left + right)/2;
if(target > nums[middle]){
left = middle + 1;
}else if(target < nums[middle]){
right = middle;
}else{
return middle;
}
}
return -1;
}
}
注意:整个函数的返回值为int类型,因此一定要注意,函数的最后应当提供一个返回值。
27.移除元素
给你一个数组 nums
和一个值 val
,你需要 原地 移除所有数值等于 val
的元素。元素的顺序可能发生改变。然后返回 nums
中与 val
不同的元素的数量。
假设 nums
中不等于 val
的元素数量为 k
,要通过此题,您需要执行以下操作:
- 更改
nums
数组,使nums
的前k
个元素包含不等于val
的元素。nums
的其余元素和nums
的大小并不重要。 - 返回
k
。
1.暴力求解
class Solution {
public int removeElement(int[] nums, int val) {
int size = nums.length-1;
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+1;
}
}
注意:这里的size存储的是数组的下标值,在这里最终返回的应当是数组的真实长度,所以为size+1.
2.双指针法
思想:用单个for循环实现双层for循环的操作。其中fast指针指向更新后的数组中的值,low指向要更新的数组中的位置。那么最后low返回的就是更新后数组的长度。
class Solution {
public int removeElement(int[] nums, int val) {
int low = 0;
for(int fast = 0;fast < nums.length;fast++){
if(nums[fast] != val){
nums[low++] = nums[fast];
}
}
return low;
}
}
977.有序数组的平方
给你一个按 非递减顺序 排序的整数数组 nums
,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
示例 1:
输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]
示例 2:
输入:nums = [-7,-3,2,3,11]
输出:[4,9,9,49,121]
思想:用双指针法请求,因为本身为非递减排序,也就是两端的元素值最大。所以直接用俩个指针从俩端比较出一个最大值,放在新的数组中即可。由于要求我们非递减排序,所以存储最大值的时候要从后往前进行存储。
class Solution {
public int[] sortedSquares(int[] nums) {
int[] result = new int[nums.length];
int left = 0;
int right = nums.length-1;
int index = nums.length-1;
while(left <= right){
if(nums[left]*nums[left] < nums[right]*nums[right]){
result[index--] = nums[right]*nums[right];
right--;
}else{
result[index--] = nums[left]*nums[left];
left++;
}
}
return result;
}
}
注意:result[index–] = nums[right–]*nums[right–];这种写法,会导致第二次使用nums值的时候,下标已经发生改变,不是原先比较的值了。