代码随想录一刷 Day1 数组

题目1:704. 二分查找 - 力扣(LeetCode)

上来先暴力解题一波

class Solution {
    public int search(int[] nums, int target) {
        //暴力解法
        for(int i=0;i<nums.length;i++)
        {
            if(nums[i]==target)
            {
                return i;
            }
        }
        return -1;
    }
}

数组长度为n的情况下时间复杂度为O(n)

之前学过算法但是一年没刷题忘记了TT

二分法:
使用注意事项:注意边界
1.左闭右闭
class Solution {
    public int search(int[] nums, int target) {
        //二分查找
        // Arrays.sort(nums);
        int i=0;
        int j=nums.length-1;//因为是左右闭合 最左右均能取到
        while(i<=j)//等号这种情况 当i=4 m=5 j=6 target=nums[4]时即可验证 i和j同时指向一处时仍有意义
        {
            int k=i+(j-i)/2;
//             当我们要计算左右边界的中间值时,如果左右边界的值非常大,相加可能会导致整数溢出。
//例如,如果 left 是一个很大的正整数,而 right 是一个接近最大整数值的负整数,它们相加可能会超出整数所能表示的范围。 
//为了避免这种情况,我们使用 (right - left) / 2 来计算中间值。这样计算是安全的,因为我们先计算了两个边界值的差值,然后再除以 2。差值计算不会导致溢出,因为两个边界值的差值一定不会超过它们的和。 
//通过这种方式,我们可以确保在任何情况下都能够正确计算数组的中间索引,而不会因为边界值的大小而产生错误的结果。
            if(target==nums[k])
            {
                 return k;
            }
            else if(target<nums[k])
            {
                j=k-1;
                continue;
            }else{
                i=k+1;
                continue;
            }
        }
        return -1;
    }
}

我觉得比较重要的点就是自己在纸上画一画模拟一下过程 知道判断结束后i和j应当怎么变化。以及i=j这种临界条件的判定 写注释的地方尤其要注意

左闭右闭的情况搞清楚了 左闭右开就很容易理解 有点像链表里面的链表头那个意思
class Solution {
    public int search(int[] nums, int target) {
        //二分查找
        // Arrays.sort(nums);
        int i=0;
        int j=nums.length;//因为是左闭右开 最右取不到
        while(i<j) //i=j时无意义
        {
            int k=i+(j-i)/2;
            if(target==nums[k])
            {
                 return k;
            }
            else if(target<nums[k])
            {
                j=k;
                continue;
            }else{
                i=k+1;
                continue;
            }
        }
        return -1;
    }
}
做完了看题解 发现有意思的一个小点:

(j-i)/2 可以用 (j-i)>>1代替。位运算比除法运算更高效。在许多编程语言中,位运算比除法运算要快得多。因此,使用 (j - i) >>1 可以获得更好的性能和执行速度。

相关题目:

35. 搜索插入位置 - 力扣(LeetCode)

啊啊啊真的很笨 看到题目中要插入就没细想 做错了

其实正确解法和二分法很像,只需思考没有的元素应当插入在哪:没有元素时,i>j,在此上一步一定是i=j=m,i>j时,无论是因为i=m+1(意思就是target比nums[m]大,此时i=m+1恰好指向应该插入的位置)引起的i>j,还是j=m-1(意思是target比现存nums[m]小,i恰好就是该插入的位置)引起的i>j, i的位置就是要插入的位置,实在不明白就画个图TAT。

class Solution {
    public int searchInsert(int[] nums, int target) {
        if(target<nums[0])
        return 0;
        if(target>nums[nums.length-1])
        return nums.length;
        int i=0;
        int j=nums.length-1;
        while(i<=j)
        {
            int m=i+((j-i)>>2);
            if(target==nums[m])
            {
                return m;
            }else if(target>nums[m])
            {
                i=m+1;
                continue;
            }else{
                j=m-1;
                continue;
            }
        }
        return i;
    }
}

一个小错误:(j-i)>>2要再用()括一层 因为位运算优先级小于减法运算。。

 

 

34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)

上来就是一个错误:

 未考虑到数组为空的情况

自己写的:笨笨的 用的快慢指针的方法

应该可以用二分法

还没做出来。。。

原始代码:

  • 最坏情况下的时间复杂度是 O(n),其中 n 是数组的长度。在最坏情况下,需要遍历整个数组,直到找到目标值或确定不存在目标值。
  • 最好情况下的时间复杂度是 O(1),当数组为空或目标值不在数组范围内时,可以立即返回结果。

优化后的代码:

  • 最坏情况下的时间复杂度是 O(log n),其中 n 是数组的长度。通过使用二分查找,可以将查找范围在每次迭代中减半,从而提高查找效率。
  • 最好情况下的时间复杂度是 O(1),当数组为空或目标值不在数组范围内时,可以立即返回结果。



27. 移除元素 - 力扣(LeetCode)

快慢指针法:非常巧妙的方法,用i对数组进行遍历,用l和f两个快慢指针指示如何移动数组元素的位置。

class Solution {
    public int removeElement(int[] nums, int val) {
// 无需考虑数组中超出新长度后面的元素 
    int length=nums.length;
    int f=0;//快指针
    int l=0;//慢指针
    for(int i=0;i<nums.length;i++)
    {
        //i想象成移动的红框 对这个数组遍历,对每一个元素都做出判定
        //快慢指针就起到一个指示的作用 每次检测到一个val 快指针就要比慢指针快走一步
        if(nums[i]==val)
        {
            f++;//有=val时,本轮循环i和f均++ 若无连着的val值,将在下一轮中用nums[f]覆盖本轮nums[l].若有连续val值,则会发生i和f继续前进,直到Nums[i]!=val
            length--;//每判定一个val length-1
        }else{
            nums[l++]=nums[f++];//没有=val时,l,f随着i一起变化
        }
    }
        return length;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值