认识复杂度和简单排序算法 | 算法学习 Day1 基础部分

发布于:2023-01-04 ⋅ 阅读:(193) ⋅ 点赞:(0)

该文章基于B站视频:一周刷爆LeetCode,算法大神左神…
在这里插入图片描述

1,时间复杂度

常数时间的操作
一个操作如果和样本的数据量没有关系,每次都是固定时间内完成的操作,叫做常数操作
时间复杂度为一个算法流程中,常数操作数量的一个指标。常用O(读作big O)来表示。具体
来说,先要对一个算法流程非常熟悉,然后去写出这个算法流程中,发生了多少常数操作,
进而总结出常数操作数量的表达式

在表达式中,只要高阶项,不要低阶项也不要高阶项的系数,剩下的部分如果为f(N),那
么时间复杂度为O(f(N))。
评价一个算法流程的好坏,先看时间复杂度的指标,然后再分析不同数据样本下的实际运行
时间
(当时间复杂度相同,或已知数据量时),也就是“常数项时间”,以下为举例:
O():是指最差情况下算法的时间复杂度。

package Day1;

public class Test {
    public static void process1(){
        int N=1000;
        int a=0;
        for (int i = 0; i < N; i++) {
            a=2+5;
            a=4*7;
            a=6*8;
        }
    }
    public static void process2(){
        int N=1000;
        int a=0;
        for (int i = 0; i < N; i++) {
            a=3|6;
            a=3&4;
            a=4^785;
        }
    }
    public static void main(String[] args) {
        Test test=new Test();
        process1();
        
        process2();
    }
}

无论系数多大,都跟系数没有关系,无论低阶项多大都与其无关,因为在数据量大到一定规模时,一定是高阶项
的影响更大

2,选择排序:

选择排序是最为简单的排序方式,依次选取最小值向前填充直到排序完毕
时间复杂度O(N^2),额外空间复杂度O(1)
参考代码:

package Day1;

public class SelectionSort {
    public static void SelectionSort(int arr[]) {
        if (arr == null || arr.length < 2) {
            return;
        }
        for (int i = 0; i < arr.length - 1; i++) {
            int minIndex = i;
            for (int j = i + 1; j < arr.length; j++) {
                minIndex = arr[j] < arr[minIndex] ? j : minIndex;

            }
            swap(arr, i, minIndex);
        }
    }

    public static void swap(int arr[], int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

    public static void main(String[] args) {
        int[] arr = new int[5];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = arr.length - i;
        }
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
        SelectionSort(arr);
        System.out.println(" SelectionSort(arr);");
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }

    }
}

3,冒泡排序

在数组中依次比较相邻两个位置,数据大的位置排到右边,排序完毕后再次从数组开头排序,直到每次比较两个位置时数据大的都在右边。
时间复杂度O(N^2),额外空间复杂度O(1)
参考代码:

package Day1;

public class BubbleSort {
    public static void BubbleSort(int[] arr) {
        if (arr == null || arr.length < 2) {//去除无效和无法排序的数组
            return;
        }
        for (int e = arr.length-1; e >0 ; e--) {
            for (int i = 0; i < e; i++) {
                if (arr[i]>arr[i+1]){
                    swap(arr,i,i+1);
                }
            }
            
        }
    }
    //交换arr的i位置和j位置上的值,异或运算
    public static void swap(int[] arr,int i,int j) {
        arr[i]=arr[i]^arr[j];
        arr[j]=arr[i]^arr[j];
        arr[i]=arr[i]^arr[j];
    }
    public static void main(String[] args) {
        int[] arr = new int[5];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = arr.length - i;
        }
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
       BubbleSort(arr);
        System.out.println("   BubbleSort(arr);");
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }

    }
}

3,异或运算

指不同为1,相同为0,也可以理解为二进制的无进位相加;

原理:
0^N=N;
N^N=0;

 //交换arr的i位置和j位置上的值,异或运算
    public static void swap(int[] arr,int i,int j) {
        arr[i]=arr[i]^arr[j];
        arr[j]=arr[i]^arr[j];
        arr[i]=arr[i]^arr[j];
    }

注意:该方法的前提是arr[i]在内存中的位置必须和arr[j]的位置不同
如当i=j时,该位置的值会变成0;

3.1面试题举例:

1, 已知一个数组中只有一组数出现了奇数次其他数都是偶数次,求该出现奇数次的数

package Day1;

public class Test {

    public static void main(String[] args) {
        int []arr=new int[]{2,1,3,2,1,3,3};
        int eor=0;
        for (int i = 0; i < arr.length; i++) {
            eor=eor^arr[i];//相当于偶数次各自异或得到的结果是奇数次的数
        }
        System.out.println(eor);//结果为3
    }
}

2, 已知一个数组中只有两组数出现了奇数次其他数都是偶数次,求该出现奇数次的数

package Day1;

public class Test {

    public static void main(String[] args) {
        int[] arr = new int[]{2, 1, 3, 2, 1, 3, 3, 4};
        int eor = 0;
        for (int i = 0; i < arr.length; i++) {
            eor = eor ^ arr[i];
        }
        //eor=a^b;
        //eor!=0
        //eor必然有一个位置上是1
        int rightOne = eor & (~eor + 1);//提取出最右侧的1
        int eor1=0;
        for (int cur:arr){
            if((cur&rightOne)==1){
                eor1^=cur;
            }
        }
        System.out.println(eor1+" "+(eor^eor1));
    }
}

4,插入排序

从0~0位,0到1位,0到2位…依次从小到大排序,其中每一次最大位与它前面位置进行数据比较,当其小于前位时进行交换,前位再与其前面的位置进行比较,直到该数值不小于前位的数值:
跟数据状况无关,执行的次数是一样的
时间复杂度O(N^2),额外空间复杂度O(1)
参考代码:

package Day1;

public class insertionSort {
    public static void insertionSort(int[] arr) {
        if (arr == null || arr.length < 2) {//去除无效和无法排序的数组
            return;
        }
        for (int i = 1; i < arr.length; i++) {//0~i范围内做到有序
            for (int j = i-1; j >=0&&arr[j]>arr[j+1] ; j--) {//到i位置时,做到了0~i-1有序,此时j为0~i-1最大的数,
                swap(arr,j,j+1);
            }

        }
    }
    //交换arr的i位置和j位置上的值,异或运算
    public static void swap(int[] arr,int i,int j) {
        arr[i]=arr[i]^arr[j];
        arr[j]=arr[i]^arr[j];
        arr[i]=arr[i]^arr[j];
    }
    public static void main(String[] args) {
        int[] arr = new int[5];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = arr.length - i;
        }
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
        insertionSort(arr);
        System.out.println(" insertionSort(arr);");
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }

    }
}

5,二分法

1)在一个有序数组中,找某个数是否存在

2)在一个有序数组中,找>=某个数最左侧的位置

3)局部最小值问题

6,对数器

对数器的概念和使用
1,有一个你想要测的方法a
2,实现复杂度不好但是容易实现的方法b
3,实现一个随机样本产生器
4,把方法a和方法b跑相同的随机样本,看看得到的结果是否一样。
5,如果有一个随机样本使得比对结果不一致,打印样本进行人工干预,改对方法a或者
方法b
6,当样本数量很多时比对测试依然正确,可以确定方法a已经正确


网站公告

今日签到

点亮在社区的每一天
去签到