[每日算法220505] 二分法与复杂度

Posted 如何在5年薪百万

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[每日算法220505] 二分法与复杂度相关的知识,希望对你有一定的参考价值。

今日题目

  • 二分法查找有序数组
  • 二分法解决局部最小值问题

今日心得

  • [局部最小]就是典型的纯算法题目,包含了很多隐藏的条件,如果不是事先准备。绝无可能在短时间内给出答案。
  • 抽象算法出来,需要通过一些具体的案例,用笔和纸演算。在脑中推算效率不高,大脑需要记忆太多内容。
  • 既要根据案例演算,也需要跳过细节,快速抽象出模型。然后通过对数器快速生成测试数据,根据测试结果调整算法。

算法编码

二分法查找有序数组

package find;

import math.Comp;
import sort.InsertSort;

/**
 * @ClassName BsFind
 * @Description 有序数组中,二分法找数字
 * @Author kouryoushine
 * @Date 2022/5/5 20:59
 * @Version 1.0
 */

/**
 * 无论查找=,>=,<=哪个结果,最终是二分法什么时候返回的差别。过程都是不断到的重复二分查找,达成条件跳出。
 */
public class BsFind 
    public static void main(String[] args) 

        int MaxLength=300;
        int MaxValue=100;
        int testTimes=10000;
        for (int i = 0; i < testTimes; i++) 
            int[] arr = Comp.randomIntArray(MaxLength,MaxValue);
            InsertSort.InsertSort(arr);
            int num= (int)(Math.random()*999);

            if (firstNumIndex(arr, num)!=firstNumIndex(arr, num))
                System.out.println("wronng ");
            

        



    
    public static boolean exist(int [] arr,int num)
        for(int i=0;i<arr.length;i++)
            if (arr[i]==num)
                return true;
            

        
        return false;
    

    public static int firstNumIndex(int [] arr,int num)
        for(int i=0;i<arr.length;i++)
            if (arr[i]==num)
                return i;
            

        
        return -1;
    

    public static boolean find(int[] arr, int num) 


        if (arr == null || arr.length < 1) 
            return false;
        
        int L = 0;
        int R = arr.length-1;
        //在[L,R]范围内查找
        while (L<=R)
            int midIndex = (L + R) / 2;
            if (num<arr[midIndex])
                R=midIndex-1;
            else if(num>arr[midIndex])
                L=midIndex+1;
            else 
                return true;
            
        
        return false;
    

    /**
     * 查询>=num的最左侧的值
     * - 原理:同二分法一样,不断遍历仅仅改变条件。获取到最后一个>=num的midIndex即可。
     * @param arr
     * @param num
     * @return
     */
    public static int mostLeftNoLessNumIndex(int[] arr, int num) 

        int L = 0;
        int R = arr.length-1;
        int midIndex=-1;
        if (arr == null || arr.length < 1) 
            return midIndex;
        
        //在[L,R]范围内查找
        while (L<=R)
            midIndex = (L + R) / 2;
            if (num<=arr[midIndex])
                R=midIndex-1;
            else if(num>arr[midIndex])
                L=midIndex+1;
            
        
        return midIndex;
    



查找局部最小值

package find;


/**
 * @ClassName MinLocal
 * @Description TODO
 * @Author kouryoushine
 * @Date 2022/5/5 22:47
 * @Version 1.0
 */
//tip:理解最小局部的值,并且深入理解边界条件,并抽象简化是算法的难点。如果get不到这些抽象的条件,是无论如何写不出来结果的。
// 二分法不一定只能用于有序的场景。只要任何一次有目标值,都可以使用二分法。
public class MinLocal 

    public static void main(String[] args) 
        int maxLength=100;
        int maxValue=1000;
        int testTimes=100000;
//       int arr[] = 235,106,856,483,213,264,108,56,476,450,488,872;
//        minLocalNum(arr);
        for (int i = 0; i <testTimes; i++) 
            int [] arr = randomArray(maxLength,maxValue);
            int index = 0;
            try 
                index = minLocalNum(arr);
             catch (Exception e) 
//                System.out.println(Arrays.asList(arr));
                printArray(arr);
            
            if(!isMinLocal(arr,index))
                System.out.println("Not MiniLocal!!! i="+index);
                printArray(arr);
                break;
            
        


    


    //局部最小定义
    // 数组无序,相邻不等
    // 0<1 0是局部最小
    // N-2 > N-1 N-1局部最小
    // 注:0<1 && N-2<N-1时候,说明必然之间必然存在局部最小
    //   i<i-1 && i <i +1 ,则i是局部最小
    //知识点: 斜下箭头\\ ,协商箭头/之间必然存在局部最小。(如果数组任意两组相邻的数,如果左边相邻数Desc,右侧Asc,则比存在局部最小)

    //找到任意一个局部最小的数字
    public  static int minLocalNum(int [] arr)
        if(arr==null || arr.length==0)
            return -1;
        

        int N= arr.length;
        if (N==1)
            return 0;
        
        if(arr[0]<arr[1])
            return 0;
        
        if(arr[N-2]>arr[N-1])
            return N-1;
        

        int L=0;
        int R=N-1;
        int ans=-1;
        while (L<=R)
            int mid=(L+R)/2;
            if(mid==0) //刚好剩两个数,mid取了0位置时避免报错。这种情况也可以根据L,R谁小返回谁(但不太容易理解,引入新的知识复杂化了)
                mid=1;
            
            if(arr[mid]<arr[mid-1] && arr[mid]<arr[mid+1])
                ans=mid;
                break;
            
            if(arr[mid-1]<arr[mid])
                R=mid-1;
                continue;
            
            if(arr[mid+1]<arr[mid])
                L=mid+1;
                continue;
            

        

        return ans;
    

    //for test
    public static boolean isMinLocal(int [] arr,int index)
        if(arr==null || arr.length==0)
            return -1==index;
        

        int N= arr.length;
        if (N==1)
            return true;
        
        if(arr[0]<arr[1])
            return 0==index;
        
        if(arr[N-2]>arr[N-1])
            return N-1==index;
        

        if(arr[index]<arr[index-1] && arr[index]<arr[index+1])
            return true;
        else 
            return false;
        

    
    //for test
    public static int [] randomArray(int maxLength,int maxValue)
        int len=(int)(Math.random()*maxLength);
        int [] arr= new int[len];

        for (int i = 1; i < len; i++) 
            arr[0]=(int)(Math.random()*maxValue);
            do 
                arr[i]=(int)(Math.random()*maxValue);
            while (arr[i]==arr[i-1]);//相邻不重复
        
        return arr;
    

    public static void printArray(int []arr)
        StringBuffer stringBuffer=new StringBuffer("");
        for (int i = 0; i < arr.length; i++) 
            stringBuffer.append(","+arr[i]);
            System.out.println("index="+i+" value="+arr[i]);
        
        System.out.println(stringBuffer.append(""));
    




以上是关于[每日算法220505] 二分法与复杂度的主要内容,如果未能解决你的问题,请参考以下文章

[每日算法220505] 二分法与复杂度

每日一算法|计数排序---第九天

每日算法基础算法——浮点数二分查找[数的三次方根](六

贪心+二分查找:最长上升子序列(3.14 leetcode每日打卡)

数据结构与算法之-二分查找

算法 - 二分法查找