代码随想录的第一天
704:二分查找
暴力算法
var search = function(nums, target) {
let tem = -1
for (let i = 0; i< nums.length; i++) {
if (target === nums[i]) {
tem = i
}
}
return tem
};
二分算法
左闭右闭:
var search = function(nums, target) {
let left = 0, right = nums.length - 1
while (left <= right) {
const temp = Math.floor((left + right) / 2)
if (nums[temp] === target) {
return temp
} else if (nums[temp] < target) {
left = temp + 1
} else if (nums[temp] > target) {
right = temp - 1
}
}
return -1
};
左闭右开:
var search = function(nums, target) {
let left = 0, right = nums.length
while (left < right) {
const temp = Math.floor((left + right) / 2)
if (nums[temp] === target) {
return temp
} else if (nums[temp] < target) {
left = temp + 1
} else if (nums[temp] > target) {
right = temp
}
}
return -1
};
思路:根据区间的边界的是否闭合来判断
1、判断右边是否闭合:闭合即包括,长度自然需要减去一(长度溢出);非闭合等于长度就行,相当于一个用边界进行处理,一个用边界里面的内容进行处理
2、左右是否相等:闭合1=1成立,不闭合1=1不成立
3、当目标值小于中间值:闭合时,需要减一,因为边界不包含,要去下一个边界;非闭合时,用的是边界中的内容,不需要减一
27:移除元素
暴力算法:
不符合题意
var removeElement = function(nums, val) {
for (let i = 0; i < nums.length; i++) {
if (nums[i] === val) {
nums.splice(i, 1)
i--
}
}
return nums.length
};
var removeElement = function(nums, val) {
for (let i = 0; i< nums.length; i++) {
if (nums[i] === val) {
for (let j = i + 1;j < nums.length;j++) {
nums[j - 1] = nums[j]
}
i--
nums.length--
}
}
return nums.length
};
覆盖法:(取巧)
var removeElement = function(nums, val) {
let ans = 0
for (let i = 0; i < nums.length; i++) {
if (nums[i] !== val) {
nums[ans] = nums[i]
ans++
}
}
return ans
};
数组的元素位置改变了下,记录了下长度
双指针:
var removeElement = function(nums, val) {
let slow = 0,fast = 0
while (fast < nums.length) {
if (nums[fast] !== val) {
nums[slow] = nums[fast]
slow++
}
fast++
}
nums.length = slow // 也可以直接拿数组
return slow
};
思路:(双指针)
1、顾名思义需要定义两个指针,一快一慢
2、全部从0开始走,快指针走的快,走到nums.length的时候就走完了
3、快指针遇到目标值就跳过去,没有遇到就将值给慢指针,慢指针走下一个,快指针一直走,最后会把目标值都放在数组最后,慢指针走过的长度就是新数组的长度
附加:
35.搜索插入位置
暴力算法
var searchInsert = function(nums, target) {
for (let i = 0; i < nums.length; i++) {
if (nums[i] >= target) {
return i
}
}
return nums.length
};
二分算法
左闭右闭:
var searchInsert = function(nums, target) {
let left = 0,right = nums.length - 1;
while (left <= right) {
const mid = Math.floor((left + right) / 2)
if (nums[mid] === target) {
return mid
} else if (nums[mid] < target) {
left = mid + 1
} else if (nums[mid] > target) {
right = mid - 1
}
}
return left
};
左闭右开:
var searchInsert = function(nums, target) {
let left = 0,right = nums.length;
while (left < right) {
const mid = Math.floor((left + right) / 2)
if (nums[mid] === target) {
return mid
} else if (nums[mid] < target) {
left = mid + 1
} else if (nums[mid] > target) {
right = mid
}
}
return left
};
思路:
1、和二分查找基本一样
2、为什么最后返回left?需要注意当left < 或者 <= right的时机,是左边高于右边,那么上一步的操作必然是left = mid + 1,那么就是刚好没找到目标值跳了过去,所以返回上一步的left
34.在排序数组中查找元素的第一个和最后一个位置
暴力解法:
var searchRange = function(nums, target) {
let arr = []
for (let i = 0; i<nums.length;i++) {
if (nums[i] === target) {
arr.push(i)
}
}
return arr.length > 0 ? [arr[0], arr[arr.length - 1]] : [-1,-1]
};
二分算法:
var searchRange = function(nums, target) {
let ans = [-1,-1]
const leftIndex = getIndex(nums, target, true)
const rightIndex = getIndex(nums, target, false) - 1
if (leftIndex <= rightIndex && rightIndex < nums.length && nums[leftIndex] === target && nums[rightIndex] === target) {
ans = [leftIndex, rightIndex]
}
return ans
}
const getIndex = (nums, target, type) => {
let left = 0, right = nums.length - 1, ans = nums.length;
while (left <= right) {
const mid = Math.floor((left + right) / 2)
if (nums[mid] > target || (type && nums[mid] === target)) {
right = mid - 1
ans = mid
} else {
left = mid + 1
}
}
return ans
}
思路:
1、首先需要找到左右的各自边界值,所以定义一个函数去进行寻找
2、左边:当目标值大于或者等于的时候,都需要往左边移动,因为需要找的是左边界,当右边刚好移动到左边非目标值的时候,左边界会大于右边界,得出之前存的右边界最后一次值
3、右边:寻找的是目标值过一的位置,所以最后需要去减去一得到正确下标