首页 > 其他分享 >蓝桥杯——查找的妙趣

蓝桥杯——查找的妙趣

时间:2023-01-05 15:37:00浏览次数:44  
标签:arr return 递归 int 妙趣 mid 蓝桥 查找

一、查找

1.1 递归式二分查找

  • 作为查找的必学算法,二分查找大家一定不陌生,通过前面我们所学的递归,那么我们继续强化递归思想,将二分查找转换成递归的方式。
  • 任何循环都能改成递归,递归也可以改成任何循环。

算法思想:

  • 全范围内二分查找
    • 等价于三个子问题

      • 左边找(递归):缩小范围,可用递归,并且重复

      • 中间比

      • 右边找(递归):缩小范围,可用递归,并且重复

注意:

  • 左查找和右查找只选其中一个

  • 递归如果画图就会发现,其实是一个类似树的样子,有线性的,有二分的,三分的...

  • 二分查找就像下面这样,但是每一次都会舍去一半,这也是二分查找效率高的原因

     /**
     * 递归式二分查找
     * @param arr 数组
     * @param low 左指针
     * @param high 右指针
     * @param value 查找值
     * @return
     */
    public static int binarySearch(int[] arr, int low, int high, int value) {
        // 递归三步走:3. 找出口
        if(low > high) return -1;
        int mid = low + (high - low)/2;
        if(value < arr[mid]) {
            // 找重复、找变化:对左半部分进行二分查找,最后返回的是我们查找的结果
            return binarySearch(arr,low, mid-1, value);
        }
        else if(value > arr[mid]) {
            // 找重复、找变化:对右半部分进行二分查找,最后返回的是我们查找的结果
            return binarySearch(arr,mid+1, high, value);
        }
        else return mid;
    }

1.2 旋转数组最小数字

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1.

  • 最小值一定在无序的那边,并且在最大值的右侧,因为我们题中给的就是有序递增序列。
  • 看到有序递增序列的字眼,我们直接就能想到二分查找。
  • 此题也是二分查找的一种变形
	public static int ef(int[] arr) {
        int low = 0;
        int high = arr.length - 1;
        // 没有翻转的情况
        if(arr[low] < arr[high]) return arr[low];
        while (low <= high) {
            int mid = low + ((high - low) >> 1);
            if (arr[mid] >= arr[low]) {
                // 中间值大于左边开始元素,则左边是有序的,最小值一定藏在右边
                low = mid;
            } else {
                high = mid;
            }
        }
        // 因为最小值一定在右侧
        return arr[high];
    }

1.3 在有空字符串中的有序字符串查找

有个排序后的字符串数组,其中散布着一些空字符串,编写一个方法,找出给定字符串(肯定不是空字符串)的索引。

  • 这个题就不画图了,非常简单,就是当我们中间mid取到空字符串时候,我们移动mid指针,直到不指向空为止。
     public static int indexOf(String[] arr, String p) {
        int begin = 0;
        int end = arr.length - 1;
        while(begin <= end) {
            int mid = begin + ((end - begin) >> 1);
            while(arr[mid].equals("")) {
                mid++;
            }
            if(arr[mid].compareTo(p) > 0) {
                end = mid - 1;
            }else if(arr[mid].compareTo(p) < 0) {
                begin = mid + 1;
            }else {
                return mid;
            }
        }
        return -1;
    }

1.4 找出最长连续递增子序列

(1,9,2,5,7,3,4,6,8,0)中最长的递增子序列为(3,4,6,8)

  • 这个题非常的经典,我们可以采用双指针策略,也称之为滑动窗口算法。
  • 模拟一个窗口进行滑动,最后窗口内的区域就是我们想要的答案。

	public static int zczxl(int[] arr) {
        // 用于存放结果
        int temp = 0;
        for (int i = 0; i < arr.length; i++) {
            // 滑动窗口右指针
            int right = i+1;
            int count = 0;
            // 1.当右指针扫描到最后 或者 符合递增条件时
            while(right < arr.length && arr[right] > arr[i]) {
                // 2.符合条件,我们让右指针继续移动,扩大我们的窗口,直到移动到不符合条件为止
                right++;
                i++;
                count++;
            }
            // 3.更新结果,取最优解,也是最大值。
            temp = temp < count+1 ? count+1 : temp;
            // 4.我们通过更新i,也就是刷新了左指针,让左侧窗口右移
        }
        return temp;
    }

二、 梦回递归

2.1 小白上楼梯

小白正在上楼梯,楼梯有n阶台阶,小白一次可以上1阶,2阶或者3阶,实现一个方法,计算小白有多少种走完楼梯的方式。

  • 我们仍然再练习其它算法的同时,不忘记我们的递归训练。

  • 和斐波那契数列很相似,不过变成了递归三分支的

  • 我们通过逆推的方式,可以判断最后上台阶只有三种模式,一种是差一步、第二种差两个台阶、第三种差三个台阶

  • 将这三种情况子问题我们通过递归求出后,汇总即可。

	public static int slt(int n) {
        // 3. 找出口
        if(n == 0) return 0;
        if(n == 1) return 1;
        if(n == 2) return 2;
        if(n == 3) return 4;
        // 1.找重复
        // 2.找变化
        return slt(n-1) + slt(n-2) + slt(n-3);
    }

2.2 设计一个高效的求a的n次幂的算法

解法一:O(n)

  • 这种解法正常人都能想出来
	/**
     * a的n次幂
     * @param a
     * @param n
     * @return
     */
    public static int pow1(int a, int n) {
        int res = 1;
        for (int i = 0; i < n; i++) {
            res *= a;
        }
        return res;
    }

解法二:
既然解法一是O(n),那么我们如果想要再次优化算法的时间,必然是logN级别的

  • 81 = 3^2 * 3^2 = 3^4
  • 所以我们先通过阶乘求其一部分值,最后通过递归解决另一部分值,让二者相乘就是我们的答案!
  • 还是非常的应用了:递归自己干一部分,另一部分交给别人的思想!
    public static int pow(int a, int n) {
        int res = a;
        int ex = 1;
        if(n == 0) return 1;
        // 通过阶层,我们先进行乘一部分
        while((ex<<1) <= n) {
            res *= res;
            ex <<= 1;
        }
        return res * pow(a,n-ex);
    }

三、结尾

  • 对于蓝桥杯查找知识内容就总结这么多,若想深入学习等待后续更新。
  • 我将会继续更新关于蓝桥杯方向的学习知识,感兴趣的小伙伴可以关注一下。
  • 文章写得比较走心,用了很长时间,绝对不是copy过来的!
  • 尊重每一位学习知识的人,同时也尊重每一位分享知识的人。
  • 标签:arr,return,递归,int,妙趣,mid,蓝桥,查找
    From: https://www.cnblogs.com/lx-meteor/p/17027709.html

相关文章

  • 一个查找mysql数据库无主键表的脚本
    说明:遍历所有的库表然后查询是否具有主键/bin/bashdb_host=172.19.211.2#dbipdb_name_list="chimessoxrayintcommpultus"#填写db_name支持多个数据库,以空格隔......
  • c++ 查找目录下的子目录及文件
    c++读取指定目录下的所有目录名称+文件名称-远征i-博客园(cnblogs.com) 文件句柄的类型long如果不行试试longlong 另外:使用了批处理,这篇很好CMD批处理循环......
  • 数位排序【第十三届蓝桥杯省赛C++C组】
    数位排序小蓝对一个数的数位之和很感兴趣,今天他要按照数位之和给数排序。当两个数各个数位之和不同时,将数位和较小的排在前面,当数位之和相等时,将数值小的排在前面。例如......
  • Java8中比较器和收集器的常用示例-排序、流转集合、分组、分区、查找最大最小值
    场景Java8新特性-Stream对集合进行操作的常用API:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/126070657前面讲Stream的常用api。下面讲比较器和收集器......
  • MongoDB时间范围查找
    1.查询时间范围,且模糊匹配message列中含“api”字符串的记录db.collection_fee.find({'time':{$gte:ISODate("2023-01-05T09:58:51.122Z"),$lte:ISODate("2......
  • 查找php-fpm
    [root@VM-4-6-centos/]#find/-namephp-fpm/opt/remi/php74/root/usr/sbin/php-fpm/etc/opt/remi/php74/sysconfig/php-fpm/var/opt/remi/php74/log/php-fpm/var/opt/r......
  • 蓝桥杯真题(DP)
    装饰珠解题思路:根据题意,6件装备这个信息没有用,因为最终是按照所有装备中装饰物的总数来算的。看数据范围,等级只有1、2、3、4,并且1级的可以任意放,2级的只能放2、3、4级,3......
  • 蓝桥真题——卡片
    题目卡片标签:填空题2021省赛代码#方法1importosimportsys#请在此输入您的代码num=''i=1whilenum.count('1')<2021:num=''.join((num,str(i)))......
  • 蓝桥真题——最短路 & 门牌制作
    题目1最短路标签:填空题2019省赛如下图所示,G是一个无向图,其中蓝色边的长度是1、橘色边的长度是2、绿色边的长度是3。则从A到S的最短距离是多少?答案由图可......
  • 蓝桥杯——巧妙地递归
    一、切蛋糕思想对于递归,我们可以采用思想之一,切蛋糕思想。简而言之,就是将一个大问题,切成若干个小问题进行解决。递归三要素:找重复、找变化、找边界我们可以理解为,自己......