学习目标:
力扣算法:
704.二分查找
27.移除元素
具体内容:
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、第一种解法
class Solution {
public int search(int[] nums, int target) {
// 避免当 target 小于nums[0] nums[nums.length - 1]时多次循环运算
if (target < nums[0] || target > nums[nums.length - 1]) {
return -1;
}
int left = 0;
int right = nums.length - 1;
while(left <= right ){
//防止溢出,(left+right)/2运算时存在middle大于right的情况
int middle = left + (right - left)/2;
if(nums[middle] == target){
return middle;
}
if(nums[middle] > target){
right = middle -1;
}
if(nums[middle] < target){
left = middle + 1;
}
}
return -1;
}
}
2、第二种解法
class Solution {
public int search(int[] nums, int target) {
// 避免当 target 小于nums[0] nums[nums.length - 1]时多次循环运算
if (target < nums[0] || target > nums[nums.length - 1]) {
return -1;
}
int left = 0;
//保证数组的元素都会在区间内
int right = nums.length;
while(left < right ){
//防止溢出,(left+right)/2运算时存在middle大于right的情况
int middle = left + (right - left)/2;
if(nums[middle] == target){
return middle;
}
if(nums[middle] > target){
//每次二分之后保证需要的数都有存在其区间
right = middle;
}
if(nums[middle] < target){
left = middle + 1;
}
}
return -1;
}
}
对该题目存在的问题?
(1)对left和right划分出来的区间的理解:
只是保证需要的数都有存在其区间
(2)使用left+(right-left)/2的原因:
是为了防止中间值大于right,当给定的数组长度很长,待查找元素的位置靠近数组尾部时,当循环快结束时,left和right可能都会很大,还没等除以2求得平均值,left+right求和的值就已经超出了int最大范围,导致溢出错误。
27.移除元素
解题
1、暴力解法
class Solution {
public int removeElement(int[] nums, int val) {
int size = nums.length;
for(int i = 0;i < nums.length;i++){
if(nums[i] == val){
for(int j = i+1;j <= nums.length;j++){
//依次往前挪
nums[j-1] = nums[j];
}
i--; // 因为下表i以后的数值都向前移动了一位,所以i也向前移动一位
size--; // 此时数组的大小-1
}
}
}
}
2、双指针
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;
}
对该题目存在的问题?
(1)if方法体要用nums[slow++] = nums[fast],而不是按题目意思直接slow++,然后返回slow的原因:
题目描述里需要删除重复元素并返回数组长度,没有审题清楚就很容易直接与计算数组中不重复元素的个数搞混
(2)为什么最后不能直接返回数组长度的原因:
虽然最后已经删除了重复元素,但由于在逻辑结构上来讲数组他只是一串连续的空间,里面放着值,它里面是没有长度这个概念的。
复习
704.二分查找
一开始写的,存在容易犯错的地方
class Solution {
public int search(int[] nums, int target) {
//没有判断简单的情况
int left = 0;
int right = nums.length - 1;
while(left <= right){
//使用(left + right)/2会使溢出
int middle = (left + right)/2;
if(nums[middle] > target){
//逻辑要处理清理,逻辑存在错误
left = middle - 1;
}else if(nums[middle] < target){
right = middle + 1;
}else if(nums[middle] == target){
return middle;
}
}
return -1;
}
}
矫正后:
class Solution {
public int search(int[] nums, int target) {
//要注意判断这类情况
if (target < nums[0] || target > nums[nums.length - 1]) {
return -1;
}
int left = 0;
int right = nums.length - 1;
while(left <= right){
//使用(left + right)/2会使溢出
int middle = left+(right-left)/2;
if(nums[middle] > target){
//改正逻辑
right = middle - 1;
}else if(nums[middle] < target){
left = middle + 1;
}else if(nums[middle] == target){
return middle;
}
}
return -1;
}
}
27.移除元素
一开始写的,存在容易犯错的地方
class Solution {
public int removeElement(int[] nums, int val) {
int i = 0;
for(int j = 0;j < nums.length;j++){
//逻辑代码写错
if(nums[j] == val){
i++;
}
}
return i;
}
}
矫正后
class Solution {
public int removeElement(int[] nums, int val) {
// 快慢指针
int slowIndex = 0;
for (int fastIndex = 0; fastIndex < nums.length; fastIndex++) {
//改正逻辑
if (nums[fastIndex] != val) {
nums[slowIndex] = nums[fastIndex];
slowIndex++;
}
}
return slowIndex;
}
}