技术交流

算法篇

排序

比较的和非比较的排序
归并排序

分治思想的实现
merge过程

 static void merge(int[] a, int L, int R) {
        int help[] = new int[R - L + 1];//辅组数组
        int m = (L + R) >> 1;
        int p1 = L;//坑!!!写成了0   每次进来都是右边 指针一
        int p2 = m + 1;//指针二
        int i = 0;
        while (p1 <= m && p2 <= R) {
            help[i++] = a[p1] < a[p2] ? a[p1++] : a[p2++];//谁小复制谁
        }
        while (p1 <= m) {
            help[i++] = a[p1++];
        }
        while (p2 <= R) {
            help[i++] = a[p2++];
        }
        for (i = 0; i < help.length; i++) {
            a[L + i] = help[i];//每次的起始位置是L
        }
    }

    static void mergesort(int[] a) {
        if (a == null || a.length < 2) {//边界条件
            return;
        }
        mergesort(a, 0, a.length - 1);//进入递归函数
    }

    static void mergesort(int[] a, int l, int r) {
        if (l >= r) {
            return;
        }
        int m = (l + r) >> 1;
        mergesort(a, l, m);//左边递归
        mergesort(a, m + 1, r);//右边递归
        merge(a, l, r);//类似外排合并
    }

堆排序

堆结构
1.完全二叉树
2.每个节点子树上都比他的节点小或大

  1. 2*i+1


    image.png
  • heapinsert
  • heapify
  • java 实现 PriorityQueue heap;
  • 比较器
  static void heapsort(int[] a) {
        if (a == null || a.length < 2) {
            return;
        }
        for (int i = 0; i < a.length; i++) { //建堆
            heapinsert(a, i);
        }
        int size = a.length;
        swap(a, 0, --size);
        while (size > 0) {//开始循环去把一个个数换到后面去
            heapify(a, 0, size);
            swap(a, 0, --size);
        }
    }

    //    heapify 下沉
    static void heapify(int a[], int index, int heapsize) {
        int left = index * 2 + 1;
        while (left < heapsize) {
//            找左右孩子中最大的那个的下标
//            int largest = left + 1 <=heapsize && a[left + 1] > a[left] ? left + 1 : left;
            int largest = left + 1 < heapsize && a[left + 1] > a[left] ? left + 1 : left; //left 是下标 size 是数量== 情况不成立
//            找左右 index 中的下标
            largest = a[index] > a[largest] ? index : largest;//坑!largest 写成了 left
            if (largest == index) {//找到了最大  刚刚忘了!
                break;
            }
            swap(a, index, largest);//刚忘了!
            index = largest;
            left = index * 2 + 1;
        }
    }
//上浮
    static void heapinsert(int a[], int index) {
        while (a[index] > a[(index - 1) / 2]) {//照顾了==0 也不进去循环
            swap(a, index, (index - 1) / 2);
            index = (index - 1) / 2;
        }
    }

快速排序

image.png
  static int[] partition(int[] a, int l, int r) {
        int less = l - 1;//小于区域
        int more = r;//大于区域
        while (l < more) {   //l在变化 像一个指针  more 是大于区域
            if (a[l] < a[r]) {//最后一个数是标准
                swap(a, ++less, l++);
            } else if (a[l] > a[r]) {
                swap(a, --more, l);
            } else {
                l++;
            }
        }
        swap(a, more, r);
        return new int[]{less + 1, more}; //返回交换之后的等于的数组范围;
    }

    static void quicksort(int[] a) {
        if (a == null && a.length < 2) {
            return;
        }
        quicksort(a, 0, a.length - 1);
    }

    static void quicksort(int[] a, int l, int r) {
        if (l < r) {
            int[] ret = partition(a, l, r);
            quicksort(a, 0, ret[0] - 1);
            quicksort(a, ret[1] + 1, r);
        }
    }
image.png

暴力递归

暴力递归就是尝试
1,把问题转化为规模缩小了的同类问题的子问题
2,有明确的不需要继续进行递归的条件(base case)
3,有当得到了子问题的结果之后的决策过程 4,不记录每一个子问题的解
一定要学会怎么去尝试,因为这是动态规划的基础

image.png

import java.net.DatagramPacket;

public class Code06_ConvertToLetterString {

    public static int number(String str) {
        if (str == null || str.length() == 0) {
            return 0;
        }
        return process(str.toCharArray(), 0);
    }

    public static int process(char[] chs, int i) {
        if (i == chs.length) {
            return 1;
        }
        if (chs[i] == '0') {
            return 0;
        }
        if (chs[i] == '1') {
            int res = process(chs, i + 1);
            if (i + 1 < chs.length) {
                res += process(chs, i + 2);
            }
            return res;
        }
        if (chs[i] == '2') {
            int res = process(chs, i + 1);
            if (i + 1 < chs.length && (chs[i + 1] >= '0' && chs[i + 1] <= '6')) {
                res += process(chs, i + 2);
            }
            return res;
        }
        return process(chs, i + 1);
    }


    public static int dpWay(String str) {
        if (str.length() == 0 || str == null) {
            return 0;
        }
        char[] chs = str.toCharArray();
        int N = str.length();
        int[] dp = new int[N + 1];
        dp[N] = 1;
        for (int i = N - 1; i >= 0; i--) {
            if (chs[i] == '0') {
                dp[i] = 0;
            } else if (chs[i] == '1') {
                dp[i] = dp[i + 1];
                if (i + 1 < chs.length) {
                    dp[i] += dp[i + 2];
                }
            } else if (chs[i] == '2') {
                dp[i] = dp[i + 1];
                if (i + 1 < chs.length && (chs[i + 1] >= '0' && chs[i + 1] <= '6')) {
                    dp[i] += dp[i + 2];
                }
            } else {
                dp[i] = dp[i + 1];
            }

        }
        return dp[0];

    }

    public static void main(String[] args) {
        System.out.println(number("11111"));
        System.out.println(dpWay("11111"));
    }

}


动态规划

动态规划(dynamic programming)是[运筹学]的一个分支,是求解决策过程(decision process)最优化的数学方法。数学家R.E.Bellman等人在研究多阶段决策过程(multistep decision process)的优化问题时,提出了著名的最优化原理(principle of optimality),把多阶段过程转化为一系列单阶段问题,利用各阶段之间的关系,逐个求解,创立了解决这类过程优化问题的新方法——动态规划。

  • 空间换时间 把上一次运行要的结果保存下来

  • 动态规划的维度

  • 空间的复用


//最大背包问题
// weight 数组 和价值数组    bag 包容量   使之价值最大

public class Code07_Knapsack {

    public static int maxValue1(int[] weights, int[] values, int bag) {
        return process1(weights, values, 0, 0, bag);
    }

    public static int process1(int[] weights, int[] values, int i, int alreadyweight, int bag) {//bag是剩下的容量
        if (alreadyweight >= bag) { //basecase 1
            return 0;
        }
        if (i == weights.length) {//     没有物品了
            return 0;
        }
        int max = Math.max(
                process1(weights, values, i + 1, alreadyweight, bag),//不要当前包
                values[i] + process1(weights, values, i + 1, alreadyweight + weights[i], bag));//要当前包   只改'变了 alreadweight  的值
        System.out.println("max="+max);
        return max;
    }

    public static int maxValue2(int[] c, int[] p, int bag) {
        int[][] dp = new int[c.length + 1][bag + 1];//长度是length bag
        for (int i = c.length - 1; i >= 0; i--) {
            for (int j = bag; j >= 0; j--) {
                dp[i][j] = dp[i + 1][j];
                if (j + c[i] <= bag) {
                    dp[i][j] = Math.max(dp[i][j], p[i] + dp[i + 1][j + c[i]]);
                }
            }
        }
        return dp[0][0];
    }

    public static void main(String[] args) {
        int[] weights = {3, 2, 4, 7};
        int[] values = {5, 6, 3, 19};
        int bag = 11;
        System.out.println(maxValue1(weights, values, bag));
        System.out.println(maxValue2(weights, values, bag));
    }
}

树形dp问题

  • 可以向左树要信息 可以向右树要信息
  • 用黑盒和拆黑盒 ReturnType

    public static class Node {
        public int value;
        public Node left;
        public Node right;

        public Node(int data) {
            this.value = data;
        }
    }

    public static boolean isBalanced(Node head) {
        return process(head,0).isBalanced;
    }

    public static class ReturnType {
        public boolean isBalanced;
        public int height;

        public ReturnType(boolean isB, int hei) {
            isBalanced = isB;
            height = hei;
        }

    }

    public static ReturnType process(Node x,int height) {
        if (x == null) {
            return new ReturnType(true, height);//返回true 和得到的高度
        }
        ReturnType leftData = process(x.left,height+1);
        ReturnType rightData = process(x.right,height+1);
        height = Math.max(leftData.height, rightData.height);//黑盒 左右的最大高度
        boolean isBalanced = leftData.isBalanced && rightData.isBalanced
                && Math.abs(leftData.height - rightData.height) < 2;// 左右是平衡 并且 左右高度 相差小于2
        return new ReturnType(isBalanced, height);
    }

滑动窗口和单调栈结构

滑动窗口
image.png

一个数组两个指针 L R

  • L往右动
  • R往右动
    就是窗口增大还是减小
    找到窗口中的最大值/最小值(每次都去遍历 代价太高)
    引入结构
    双端队列
    头------------尾
    大------------小
    存了一个作为最大值的可能性


    image.png
单调栈结构

3 1 2 4 5 0 6
每个位置都找到下左右两侧离他最近的比他小的数
不优化 O(n^2) 的方法
单调栈 O(n)


image.png

套路为先

还有些比较重要的结构和思想
贪心 二叉树 非递归遍历 morris 遍历 哈希函数 有序表 并查集 大数据相关

你可能感兴趣的:(技术交流)