算法-基础记录

 主要是自己的学习记录,不具备体系

数组

一维数组

二维数组 

缓存与局部性原理

这里只讨论空间局部性,CPU读取内存(速度较慢)数据后,会将其放入高速缓存中,若后来计算在使用到该数据,缓存中有的话就不要读内存。而缓存的最小存储单位是缓存行(cache line),一般是64bytes,一次读的数据少了不划算,所以会读入当前数据的临近数据

所以外层循环行比外层循环列更快

链表

概述

 

 内存中存储时不连续的

 

模运算优化:模2*n时

优先级队列

实现一:无序数组

优先级相关的信息在数组中的存储是无序的,出队列时进行排序,获取优先级最大的数据,入队列时直接添加即可。

实现二:有序数组

优先级相关的信息在数组中的存储是无序的,出队列时直接获取数组尾部元素,获取优先级最大的数据,入队列时进行插入排序。

实现三: 堆实现

基于树的数据结构,通常用完全二叉树(除了最后一层其他都是填满的)实现

 

 树

 

根据前序中序遍历结果恢复树

less

中序遍历,遍历到小的加入结果中,注意因为是搜索树且中序遍历,所以比key大的就可以退出

根据前序遍历结果简历二叉搜索树

 

公共祖先:p、q都在某一节点的两侧,那么该节点就是最近的公共祖先

 B树 

在磁盘读取时通常运用到B树,相同的数据B树的高度会比avi树,红黑树、二叉搜索树等更低。

哈希表

.entrySet()是用来获取Map中所有键值对的集合,返回的是一个Set类型,其中每个元素都是一个Map.Entry对象,包含了键和值两个部分。通过遍历这个集合,可以方便地获取Map中的所有键值对并进行操作。

查找最高频单词

import java.util.*;

public class Solution819 {
    public String mostCommonWord(String paragraph, String[] banned) {
//        String[] split = paragraph.toLowerCase().split("[^A-Za-z]+");
        char[]chars = paragraph.toLowerCase().toCharArray();
        Set<String> set = Set.of(banned);
        HashMap<String,Integer>map = new HashMap<>();
        StringBuilder sb = new StringBuilder();
        for(char ch:chars){
            if(ch>='a'&&ch<='z'){
                sb.append(ch);
            }else{
                String key = sb.toString();
                if(!set.contains(key)){
                    map.compute(key,(k,v)->v==null?1:v+1);
                }
                sb = new StringBuilder();
            }
        }

        if(sb.length()>0){
            String key = sb.toString();
            if(!set.contains(key)){
                map.compute(key,(k,v)->v==null?1:v+1);
            }
        }
        int max=0;
        String maxKey=null;
        for(Map.Entry<String,Integer>e:map.entrySet()){
            Integer value=e.getValue();
            if(value>max){
                max=value;
                maxKey=e.getKey();
            }
        }
        return maxKey;

    }
}

排序算法

冒泡排序

package sort;

import java.util.Arrays;

public class bubble {
    // j未排序区域的右边界
    // 递归实现
    private static void bubbleSort(int[] a, int j) {
        if (j == 0) {
            return;
        }
        int x = 0;//优化,记录最近一次交换位置的地方
        for (int i = 0; i < j; i++) {
            if (a[i] > a[i + 1]) {
                int t = a[i];
                a[i] = a[i + 1];
                a[i + 1] = t;
                x = i;
            }
        }
        bubbleSort(a, x);
    }

    // 非递归实现
    private static void bubbleSort2(int[] a) {
        int j = a.length - 1;
        do {
            int x = 0;//优化,记录最近一次交换位置的地方
            for (int i = 0; i < j; i++) {
                if (a[i] > a[i + 1]) {
                    int t = a[i];
                    a[i] = a[i + 1];
                    a[i + 1] = t;
                    x = i;
                }
            }
            j = x;
        } while (j != 0);
    }

    public static void main(String[] args) {
        int[] a = new int[]{1, 2, 5, 6, 3, 2};
        bubbleSort(a, a.length - 1);
        System.out.println(Arrays.toString(a));
        bubbleSort2(a);
        System.out.println(Arrays.toString(a));
    }
}

选择排序

package sort;

import java.util.Arrays;

public class pick {
    private static void pickSort(int[] a) {
        for (int right = a.length - 1; right > 0; right--) {
            int max = right;
            //假定最后一个元素时最大的,与前面的元素进行比较
            for (int i = 0; i < right; i++) {
                if (a[i] > a[max]) {
                    max = i;
                }
            }
            if(max!=right) {
                swap(a, right, max);
            }
        }

    }

    private static void swap(int[] a, int i, int j) {
        int t = a[i];
        a[i] = a[j];
        a[j] = t;
    }

    public static void main(String[] args) {
        int[] a = new int[]{1, 2, 5, 6, 3, 2};
        pickSort(a);
        System.out.println(Arrays.toString(a));
    }
}

堆排序

package sort;

import java.util.Arrays;

public class heap {
    private static void heapSort(int[] a){
        heapify(a,a.length);
        System.out.println(Arrays.toString(a));
        for(int right=a.length-1;right>0;right--){
            swap(a,0,right);
            down(a,0,right);
        }
    }

    private static void swap(int[] a, int i, int j) {
        int t = a[i];
        a[i] = a[j];
        a[j] = t;
    }
    // 建堆
    private static void heapify(int[]a,int size){
        for(int i=size/2-1;i>=0;i--){
            down(a,i,size);
        }
    }
    // 下潜
    private static void down(int[] a,int parent,int size){
        int left = parent*2+1;
        int right = left+1;
        int max=parent;
        if(left<size&&a[left]>a[max]){
            max=left;
        }
        if(right<size&&a[right]>a[max]){
            max=right;
        }
        if(max!=parent){
            // 找到了更大的孩子
            swap(a,max,parent);
            down(a,max,size);
        }
    }

    public static void main(String[] args) {
        int[] a = new int[]{1, 2, 5, 6, 3, 2,7};
        heapSort(a);
        System.out.println(Arrays.toString(a));
    }
}

插入排序

package sort;

import java.util.Arrays;

public class insert {
    private static void insertSort(int[] a){
        insertion(a,1);
    }

    private static void insertion(int[] a ,int low){
        if(low==a.length){
            return;
        }
        int t=a[low];
        int i=low-1;
        // 自右向左寻找插入位置,如果比待插入元素大,则不断右移,空出插入位置
        while (i>=0&&a[i]>t){
            a[i+1]=a[i];
            i--;
        }
        // 找打插入位置
        // 1 3 6 5 对于5而言已经在while循环将5与6交换,所以无需重复赋值
        if(i+1!=low){
            a[i+1]=t;
        }
        insertion(a,low+1);
    }
    public static void main(String[] args) {
        int[] a = new int[]{1, 2, 5, 6, 3, 2};
        insertSort(a);
        System.out.println(Arrays.toString(a));
    }
}

希尔排序

相比插入排序更好,可以简单形象理解为,迈的步子更大,交换次数更少。

package sort;

import java.util.Arrays;

public class hill {
    private static void hillSort(int[] a) {
        // gap 4 2 1
        for (int gap = a.length >> 1; gap >= 1; gap = gap >> 1) {
            for (int low = gap; low < a.length; low++) {
                int t = a[low];
                int i = low - gap;
                // 自右向左寻找插入位置,如果比待插入元素大,则不断右移,空出插入位置
                while (i >= 0 && a[i] > t) {
                    a[i + gap] = a[i];
                    i--;
                }
                // 找打插入位置
                // 1 3 6 5 对于5而言已经在while循环将5与6交换,所以无需重复赋值
                if (i + gap != low) {
                    a[i + gap] = t;
                }
            }
        }
    }

    public static void main(String[] args) {
        int[] a = new int[]{1, 2, 5, 6, 3, 2};
        hillSort(a);
        System.out.println(Arrays.toString(a));
    }
}

归并排序

归并加插入,没有必要一直分治到只有一个元素,但元素个数较少时可以直接进行插入排序

单边循环快排

package sort;

import java.util.Arrays;

public class quick {
    private static void quickSortLomuto(int[] a) {
      quick(a,0,a.length-1);
    }

    private  static void  quick(int[] a,int left,int right){
        if(left>=right){
            return;
        }
        int p=partition(a,left,right);
        quick(a,left,p-1);
        quick(a,p+1,right);
    }
    private static void swap(int[] a, int i, int j) {
        int t = a[i];
        a[i] = a[j];
        a[j] = t;
    }

    private static int partition(int[] a, int left, int right) {
        int pv = a[right];//基准点元素值
        int i = left;
        int j = left;
        while (j < right) {
            if (a[j] < pv) {
                //j找的是比pv小的,找到了比较i、j的值,不相等则交换
                if (i != j) {
                    swap(a, i, j);
                }
                //i=j,i继续向前走
                i++;
            }
            j++;
        }
        swap(a, i, right);
        return i;
    }

    public static void main(String[] args) {
        int[] a = new int[]{1, 2, 5, 6, 3, 2};
        quickSortLomuto(a);
        System.out.println(Arrays.toString(a));
    }

}

双边循环快排

package sort;

import java.util.Arrays;
import java.util.concurrent.ThreadLocalRandom;

public class quickShuang {
    private static void quickSortHoare(int[] a) {
        quick(a, 0, a.length - 1);
    }

    private static void quick(int[] a, int left, int right) {
        if (left >= right) {
            return;
        }
        int p = partition(a, left, right);
        quick(a, left, p - 1);
        quick(a, p + 1, right);
    }

    private static void swap(int[] a, int i, int j) {
        int t = a[i];
        a[i] = a[j];
        a[j] = t;
    }

    private static int partition(int[] a, int left, int right) {
        // 随机选择基准点
        int idx = ThreadLocalRandom.current().nextInt(right-left+1)+left;
        swap(a,left,idx);
        int pv = a[left];//基准点元素值
        int i = left;
        int j = right;
        while (i < j) {
            while (i < j && a[j] > pv) {
                // j从右向左找小的
                j--;
            }
            while (i < j && a[i] <= pv) {
                i++;
            }
            swap(a, i, j);
        }
        swap(a, i, left);
        return i;
    }

    public static void main(String[] args) {
        int[] a = new int[]{1, 2, 5, 6, 3, 2};
        quickSortHoare(a);
        System.out.println(Arrays.toString(a));
    }

}

计数排序

package sort;

import java.util.Arrays;

public class count {
    private static void countSort(int[] a) {
        int max = a[0];
        int min = a[0];
        // min求出最小值,处理有负数的情况
        for (int i = 1; i < a.length; i++) {
            if (a[i] > max) {
                max = a[i];
            }
            if (a[i] < min) {
                min = a[i];
            }
        }
        int[] count = new int[max - min + 1];
        for (int v : a) {
            count[v - min]++;
        }
        int k = 0;
        for (int i = 0; i < count.length; i++) {
            // i代表原始数据元素,count[i]代表出现次数
            while (count[i] > 0) {
                a[k] = i + min;
                count[i]--;
                k++;
            }
        }
    }

    public static void main(String[] args) {
        int[] a = new int[]{1, 2, 5, 6, 3, 2};
        countSort(a);
        System.out.println(Arrays.toString(a));
    }
}

桶排序

将数据分段翻入每个桶中,每个桶里再排序

如果桶数据分布不均匀,优化可以求出最大值最小值决定有多少个桶

基数排序

最低有效数字,先排低位再排高位(可以理解为高位优先级、权重更大)

最小生成树

Prim算法,以顶点为中心拓展权重最小的边

Kruskal算法,每次选取最小权重的边,且加入后不构成环,也就是顶点之间不能联通(使用到了并查集)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值