算法图解笔记

二分(折半)算法 [O(log n)]

特点:1.查找的元素列表必须有序

2.所取中间数向下取整

3.当n是2的倍数时,所得结果+1

//非递归实现
public class Solution{
    public static void main(String[] args) {
        int[] my_list = {1, 2, 3, 4, 5, 6, 7};
        int temp = binary_search(my_list, 4);
        System.out.println(temp + 1);
    }
    //折半查找
    private static int binary_search(int[] list, int item) {
        int low = 0;
        int high = list.length - 1;
        int sum=0;
        while (low <= high) {
            sum++;//记录需要运行几次
            int mid = (low + high) / 2;
            if (list[mid] == item) {
                System.out.println(sum);
                return mid;//索引
            }
            if (list[mid] > item) {
                high = mid - 1;
            } else {
                low = mid + 1;
            }
        }
        return -1;
    }
}

//递归实现二分法
public static int sort(int []array,int a,int lo,int hi){
        if(lo<=hi){
            int mid=(lo+hi)/2;
            if(a==array[mid]){
                return mid+1;
            }
            else if(a>array[mid]){
                return sort(array,a,mid+1,hi);
            }else{
                return sort(array,a,lo,mid-1);
            }
        }
        return -1;
}

大O表示法

图片

数组

1.数组内的数在内存中相连

2.可以顺序访问也可以随机访问

链表

1.可以在内存中不连续

2.只能顺序访问

*需要同时读取所有元素时,链表效率更高,需要随机读取时,数组效率更高

*数组读取快,插入慢

*链表读取慢,插入快

选择排序 [O(n^2)]

如遍历所有元素,选出最大的,再遍历,选出剩下元素中最大的…

遍历一次的复杂度是O[n],遍历n次,所以复杂度O[n^2]

递归

1.自己调用自己

2.每个递归函数有两个部分

*递归条件:函数自己调用自己

*基线条件:函数不在调用自己,避免形成无限循环

3.跟循环比起来只是解决方案更清晰,并没有性能上的提升

1.先进后出

2.栈在递归中扮演重要角色

3.每次递归中的变量都储存在调用栈中(自动完成)

缺点:储存详尽的信息(调用栈可能很长)可能占用大量的内存

解决办法:1.重新编码,转而使用循环

2.使用尾递归(高级递归主题)

快速排序 [O(nlog n)]

图片

在平均情况(最佳情况)下,快速排序运行时间为O(nlog n),在最糟糕情况下,运行时间为O(n^2)不管怎么划分数组,每次都会涉及O(n)个元素,最佳情况是调用栈高度为O(log n),最糟糕情况是调用栈高度为O(n)

import java.util.Arrays;
public class Solution{
    public static void main(String[] args) {
        int[] a = {5, 3, 4, 6, 7, 8, 2, 33};
        System.out.println(sum(a.length, a));
        System.out.println(findmax(a.length, a));
        System.out.println(Arrays.toString(a));
        el(a);
        System.out.println(Arrays.toString(a));
    }
    //集合所有元素之和(递归版)
    public static int sum(int n, int[] arr) {
        if (arr == null || arr.length == 0) {
            return 0;
        }
        if (n == 1) {
            return arr[n - 1];
        } else {
            return sum(n - 1, arr) + arr[n - 1];
        }
    }
    //找集合中的最大数
    public static int findmax(int n, int[] arr) {
        int max = arr[0];
        for (int i = 0; i < n; i++) {
            if (max <= arr[i]) {
                max = arr[i];
            }
        }
        return max;
    }
    //快速排序
    public static void el(int[] arr) {
        int n = 0;
        int m = arr.length - 1;
        long start = System.nanoTime();
        //普通版
        //sortTest(arr,n,m);
        //递归版
        quickSort1(arr, n, m);
        long end = System.nanoTime();
        //程序运行时间测算(单位纳秒)
        System.out.println(end-start);
    }
    public static void sortTest(int[] arr, int n, int m) {
        if (n < m) {
            //分区界限索引
            int index = quicksort(arr, n, m);
            //左分区快速排序
            quicksort(arr, n, m - 1);
            //右分区快速排序
            quicksort(arr, n + 1, m);
        }
    }
    public static int quicksort(int[] arr, int n, int m) {
        int i = n;
        int j = m;
        int x = arr[i];
        while (i < j) {
            while (arr[j] >= x && i < j) {
                j--;
            }
            if (i < j) {
                arr[i] = arr[j];
                i++;
            }
            while (arr[i] <= x && i < j) {
                i++;
            }
            if (i < j) {
                arr[j] = arr[i];
                j--;
            }
        }
        arr[i] = x;
        return i;
    }
    //快速排序(递归)
    public static void quickSort1(int[] n, int left, int right) {
        int pivot;
        if (left < right) {
            //pivot作为枢轴,较之小的元素在左,较之大的元素在右
            pivot = partition(n, left, right);
            //对左右数组递归调用快速排序,直到顺序完全正确
            quickSort1(n, left, pivot - 1);
            quickSort1(n, pivot + 1, right);
        }
    }
    public static int partition(int[] n, int left, int right) {
        int pivotkey = n[left];
        //枢轴选定后永远不变,最终在中间,前小后大
        while (left < right) {
            while (left < right && n[right] >= pivotkey) --right;
            //将比枢轴小的元素移到低端,此时right位相当于空,等待低位比pivotkey大的数补上
            n[left] = n[right];
            while (left < right && n[left] <= pivotkey) ++left;
            //将比枢轴大的元素移到高端,此时left位相当于空,等待高位比pivotkey小的数补上
            n[right] = n[left];
        }
        //当left == right,完成一趟快速排序,此时left位相当于空,等待pivotkey补上
        n[left] = pivotkey;
        return left;
    }
}

散列表(Hashtable)[O(1)]

内部机制:实现、冲突和散列函数

散列表:结合使用散列函数和数组

缓存的数据存储在散列表中(如web服务器上)

冲突很糟糕,应该使用可以最大限度减少冲突的散列函数

一旦填装因子超过0.7,就该调整散列表的长度

避免冲突需要:1.较低的填装因子

2.良好的散列函数

广度优先算法 [O(V+E)]

广度优先算法可以用于求非加权图最短路径

搜索列表必须是队列

每检查一个节点,就将其设置为1,避免再次检查,否可能导致无限循环

无向图和有向图

检测完一度关系后再将二度关系入队,以此类推

V指节点数,E为边数

狄克斯特拉算法

1.狄克斯特拉算法用于在加权图中查找最短路径(不能用于含有负权边)

2.需要三张散列表来记录数据

*GRAPH用于记录每个节点所有的邻居以及他们间的权重

*COSTS用于储存每个节点的开销(从起点到该节点的权重)

*PARENTS用于储存每个节点的父节点

COSTS和PARENTS不断更新

贝尔曼-福德算法

该算法可以弥补狄克斯特拉算法的缺陷,可以在含有负权边的加权图中查找最短路径

贪心算法/近似算法 [O(n^2)]

1.每步都选取最优做法,因为每步都选择局部最优解,最终会得到的就是全局最优解

2.广度优先算法和狄克斯特拉算法都是贪心算法

3.NP完全问题[O(n!)]的简单定义是难解著称的,面对NP完全问题的最佳做法就是近似算法

4.如何识别NP完全算法:

*元素较少时算法的运行速度非常快,但随着元素数量的增加,速度会变得非常慢。

*涉及“所有组合”的问题通常是NP完全问题。

*不能将问题分成小问题,必须考虑各种可能的情况。这可能是NP完全问题。

*如果问题涉及序列(如旅行商问题中的城市序列)且难以解决,它可能就是NP完全问题。

*如果问题涉及集合(如广播台集合)且难以解决,它可能就是NP完全问题。

*如果问题可转换为集合覆盖问题O(2^n)或旅行商问题,那它肯定是NP完全问题。

5.贪心算法易于实现、运行速度快,是不错的近似算法

K最近邻算法(KNN)

重点在于特征抽取,可以用于推荐最相似的类型

如比较橙子和柚子,可以抽离个头大小和颜色数据化,假设有一个水果需要判断是橙子还是柚子,就可以判断距离这个水果离哪边距离更近的多,距离的测算公式是毕达哥拉斯公式

*毕达哥拉斯公式:根号下(a1-a2)2+(b1-b2)2

更多的数据也可以使用这个公式

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值