赞
踩
题目链接:704. 二分查找
文档讲解:代码随想录(programmercarl.com)
视频讲解:手把手带你撕出正确的二分法 | 二分查找法 | 二分搜索法 | LeetCode:704. 二分查找
状态:已解决
题目中已经点明了使用二分查找的方法,在升序数组 nums 中寻找目标值 target 。每次选取查找区间的中点的值与 target 进行比较,根据两者的大小关系可以进一步确定 target 可能存在的范围,缩小查找区间。每次查找都可以将查找区间缩小一半。
设置查找区间的左右端点,区间的左端点记作 p1 ,区间的右端点记作 p2 。对于查找区间中任意下标 i 位置的值,有以下三种情况:
(1)若,则 i 为所求值,返回 i ;
(2)若,则 target 所在区间为 i 右侧,更新 p1 为 i ;
(3)若,则 target 所在区间为 i 左侧,更新 p2 为 i 。
选取 i 为查找区间的中点 mid ,即。
判断停止条件如下:
(1),左开右开:
(2),左闭右开:
(3),左闭右闭:
Java代码如下:
以为例:
- class Solution {
- public int search(int[] nums, int target) {
- if(nums[0]>target||nums[nums.length-1]<target){
- return -1;
- }
- if(nums[0]==target){
- return 0;
- }
- if(nums[nums.length-1]==target){
- return nums.length-1;
- }
- int p1=0;
- int p2=nums.length-1;
-
- while(p2-p1>1){
- if(nums[p1+(p2-p1)/2]==target){
- return p1+(p2-p1)/2;
- }else{
- if(nums[p1+(p2-p1)/2]<target){
- p1=p1+(p2-p1)/2;
- }else{
- p2=p1+(p2-p1)/2;
- }
- }
- }
- return -1;
- }
- }
复杂度分析:
时间复杂度:O(logn),n为数组长度
空间复杂度:O(1)
(1)判断循环终止条件;
(2)中点。若写成,在数组长度过大时可能会造成 int 类型数据溢出。
题目链接:27. 移除元素
文档讲解:代码随想录(programmercarl.com)
视频讲解:数组中移除元素并不容易! | LeetCode:27. 移除元素
状态:已解决
首先想到暴力求解法,即遍历数组,找到与 val 相等的值后将其右侧所有元素左移,但时间复杂度较大。使用偏移量法记录每个元素偏移的位数,可以减少元素移动次数。还可以使用双指针法,定位目标值的位置,将其右侧的值填补进来,即可保证非目标值填充在数组的左侧。
设置一个额外的数组 py[nums.length] 来存储 nums 中每个数据的偏移量,即需要左移的位数。
设置初始偏移量 p=0 ,遍历数组nums ,判断其中每个数据 nums[i] 是否与 val 相等,若相等,位于数组中其右侧的数据都需向左移动一位,则偏移量 p++ 。对于数组中的每个数据,都将其对应的偏移量存入数组 py 中。
再次遍历数组 nums ,对于每个不等于 val 的数,将其向左移动,移动的位数即它对应的偏移量。最后返回值即为 p 。
Java代码如下:
- class Solution {
- public int removeElement(int[] nums, int val) {
- if(nums.length==0){
- return 0;
- }
- int[] py = new int[nums.length];
- int p=0;
- for(int i=0;i<nums.length;i++){
- if(nums[i]==val){
- p++;
- }
- py[i]=p;
- }
- for(int i=0;i<nums.length;i++){
- if(nums[i]!=val){
- nums[i-py[i]]=nums[i];
- }
- }
- return nums.length-p;
- }
- }
复杂度分析:
时间复杂度:O(n),n为数组长度
空间复杂度:O(n),n为数组长度
考虑到偏移量的计算可以与数组的移动一起完成,就不需要使用额外的数组来存储每个数据的偏移量,代码可以改进为如下形式:
- class Solution {
- public int removeElement(int[] nums, int val) {
- if(nums.length==0){
- return 0;
- }
- int p=0;
- for(int i=0;i<nums.length;i++){
- if(nums[i]==val){
- p++;
- }else{
- nums[i-p]=nums[i];
- }
- }
- return nums.length-p;
- }
- }
复杂度分析:
时间复杂度:O(n),n为数组长度
空间复杂度:O(1)
维护两个指针 left 和 right ,left 指向数组要赋值的位置, right 指向当前判断的元素。初始 left 和 right 都指向0。 right 遍历数组 nums 。
(1)当 nums[right]=val 时,right++ ;
(2)当 nums[right]!=val 时,将 right 位置的值赋给left位置,right++,left++。
Java代码如下:
- class Solution {
- public int removeElement(int[] nums, int val) {
- if(nums.length==0){
- return 0;
- }
- int left=0;
- for(int right=0;right<nums.length;right++){
- if(nums[right]!=val){
- nums[left]=nums[right];
- left++;
- }
- }
- return left;
- }
- }
复杂度分析:
时间复杂度:O(n),n为数组长度
空间复杂度:O(1)
题中说明不需保证元素的相对位置不发生变化,那么从左至右将目标值位置填充上其右侧的非目标值即可,可以减少数组操作的次数。
维护两个指针 left 和 right ,left 指向数组要赋值的位置, right 指向当前判断的元素。初始 left 指向0,right 指向 nums.length-1。当left与right不重合时:
(1)当 nums[left]=val 时,将 right 位置的值赋给left位置,right-- ;
(2)当 nums[left]!=val 时,left++。
Java代码如下:
- class Solution {
- public int removeElement(int[] nums, int val) {
- if(nums.length==0){
- return 0;
- }
- int left=0;
- int right=nums.length-1;
- while(left<=right){
- if(nums[left]==val){
- nums[left]=nums[right];
- right--;
- }else{
- left++;
- }
- }
- return left;
- }
- }
复杂度分析:
时间复杂度:O(n),n为数组长度
空间复杂度:O(1)
(1)尽可能在时间复杂度上对算法进行优化,使用尽可能小的时间复杂度,在本题中尽可能减少移动元素的次数。
(2)循环的终止条件需要仔细考量。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。