zoukankan      html  css  js  c++  java
  • 算法十八招

    第一招:动态规划算法

    动态规划思想:把问题分解为多个阶段,每个阶段执行决策,记录每一个阶段可达的状态集合(去重后),
    基于当前阶段的状态集合,通过决策,推导下一个阶段的状态结婚,动态的往前推进
    经典背包问题:有一组不同重量不可分割的物品,需要选择一些装入背包,在满足背包最大重量限制的前提下
    ,背包中物品的最大重量是多少?
    1、把问题分为多个阶段,物品是一个一个装入选择是否装入背包中,每一个物品选择是否装入背包作为一个阶段,共有物品个数个阶段
    2、每个阶段做出决策,选择是否装入该物品
    3、每个阶段做出决策前有一个当前状态集合,做出决策后也记录可达状态集合(去重)
    依次步骤动态的往前推进 阶段就是for循环 决策就是for循环里的逻辑 初始化状态集合,并在执行决策后记录可达的状态集合
    循环执行完后,即动态推进结束

    public class Packet {
        public int packet(int[] weights, int maximum) {
            int number = weights.length;
            boolean[][] states = new boolean[number][maximum+1];//true表示可达状态
            states[0][0] = true;
            if(weights[0] <= maximum) {
                states[0][weights[0]] = true;
            }
            for(int i=1; i<number; i++) {
                //装进背包
                for(int j=0; j<=maximum; j++) {
                    if(states[i-1][j] && j + weights[i] <= maximum) {
                        states[i][j + weights[i]] = true;
                    }
                }
                //不装进背包
                for(int j=0; j<=maximum; j++) {
                    if(states[i-1][j]) {
                        states[i][j] = true;
                    }
                }
            }
            for(int i=maximum; i>=0; i--) {
                if(states[number-1][i]) {
                    return i;
                }
            }
            return 0;
        }
    
        public static void main(String[] args) {
            Packet demo = new Packet();
            int[] weight = {2, 2, 4, 6, 3}; // 物品重量
            int n = 5; // 物品个数
            int w = 9; // 背包承受的最大重量
            System.out.println(demo.packet(weight, w));
        }
    
    }

    第二招:贪心算法

    贪心算法思想:每次都选择堆期望值贡献最大的数据

    经典背包问题:有一组不同重量不可分割的物品,每个物品都有对象的价值,需要选择一些装入背包,在满足背包最大重量限制的前提下,背包中物品的最大价值是多少?

    public class Packet {
        public int packet(int[] weights, int[] values, int maximum) {
            //构建性价比数组
            int number = weights.length;
            double[] w_v = new double[number];
            int[] index = new int[number];
            for(int i=0; i<number; i++) {
                w_v[i] = values[i] / weights[i];
                index[i] = i;
            }
            
            double temp = 0;
            int x = -1;
            for(int i=0; i<number-1; i++) {
                for(int j=i+1; j<number; j++) {
                    if(w_v[index[j]] > w_v[index[i]]) {
                        temp = w_v[index[j]];
                        w_v[index[j]] = w_v[index[i]];
                        w_v[index[i]] = temp;
                        
                        x = index[i];
                        index[i] = index[j];
                        index[j] = x;
                    }
                }
            }
            
            //将排好序的重量和价值分别存到数组中
            int[] w1 = new int[number];
            int[] v1 = new int[number];
            for(int i=0; i<number; i++) {
                w1[i] = weights[index[i]];
                v1[i] = values[index[i]];
            }
            
            int maxValue = 0;
            int sumWeight = 0;
            for(int i=0; i<number; i++) {
                if(sumWeight + w1[i] <= maximum) {//表示当前物品装得下
                    sumWeight += w1[i];
                    maxValue += v1[i];
                }
            }
            return maxValue;
        }
    
        public static void main(String[] args) {
            Packet demo = new Packet();
            int[] weights = {35, 30, 60, 50, 40, 10, 25}; // 物品重量
            int[] values = {10, 40, 30, 50, 35, 40, 30};// 物品价值
            int maximum = 150; // 背包承受的最大重量
            System.out.println(demo.packet(weights, values, maximum));
        }
    }

     第三招:回溯算法

    经典八皇后问题:

    //8皇后问题--回溯算法
    public class Recall {
        int[] result = new int[8];//全局或成员变量,下标表示行,值表示queue存储在哪一列
        
        public static void main(String[] args) {
            Recall recall = new Recall();
            recall.cal8queues(0);
        }
        
        public void cal8queues(int row) {//调用方式:cal8queues(0)
            if(row == 8) {//8个棋子都放置好了,打印结果
                printQueues(result);
                return;//8行棋子都放好了,已经没法再往下递归了,所以就return
            }
            for(int column=0; column<8; column++) {//每一行都有8种放法
                if(isOk(row, column)) {//有些放法不满足要求
                    result[row] = column;//第row行的棋子放到了column列
                    cal8queues(row+1);//考察下一行
                }
            }
        }
        
        private boolean isOk(int row, int column) {//判断row行column列放置是否合适
            int leftup = column-1, rightup = column+1;
            for(int i=row-1; i>=0; i--) {//逐行往上考察每一行
                if(result[i] == column) {
                    return false;//第i行的column列有棋子吗?
                }
                if(leftup >= 0) {//考察左上对角线:第i行leftup列有棋子吗?
                    if(result[i] == leftup) {
                        return false;
                    }
                }
                if(rightup < 8) {//考察右上对角线:第i行rightup列有棋子吗?
                    if(result[i] == rightup) {
                        return false;
                    }
                }
                leftup--;
                rightup++;
            }
            return true;
        }
        private void printQueues(int[] result) {//打印一个二维矩阵
            for(int row=0; row<8; row++) {
                for(int column=0; column<8; column++) {
                    if(result[row] == column) {
                        System.out.print("Q");
                    }else {
                        System.out.print("*");
                    }
                }
                System.out.println();
            }
            System.out.println();
        }
    }

    第四招:二叉树

    【递归 | 非递归】前序、中序、后序遍历

    import java.util.Stack;
    
    public class BinaryTree {
        static class Node {
            public String value;//节点存储的内容
            public Node leftNode;//左孩子
            public Node rightNode;//右孩子
            
            public Node(String value) {
                this.value = value;
            }
        }
        public static void main(String[] args) {
    /**
                     8
                   /   
                  6     7
                 /    / 
                2   3 4   5
               /
              1
     */
            Node root = new Node("8");
            Node node1 = new Node("1");
            Node node2 = new Node("2");
            Node node3 = new Node("3");
            Node node4 = new Node("4");
            Node node5 = new Node("5");
            Node node6 = new Node("6");
            Node node7 = new Node("7");
            root.leftNode = node6; root.rightNode = node7;
            node6.leftNode = node2; node6.rightNode = node3;
            node7.leftNode = node4; node7.rightNode = node5;
            node2.leftNode = node1;
            BinaryTree demo = new BinaryTree();
            demo.npreOrder(root);
            System.out.println();
            demo.ninOrder(root);
            System.out.println();
            demo.npostOrder(root);
            System.out.println();
            
            demo.preOrder(root);
            System.out.println();
            demo.inOrder(root);
            System.out.println();
            demo.postOrder(root);
            System.out.println();
        }
        
        //非递归前序遍历
        public void npreOrder(Node node){
            Stack<Node> sk=new Stack<Node>();
            Node n=node;
            while(!sk.isEmpty() || n!=null){
                if(n!=null){
                    System.out.print("->");
                    System.out.print(n.value);
        
                    sk.push(n);
                    n=n.leftNode;
                }else{
                    n=sk.pop();;
                    n=n.rightNode;
                }
            }
        }
        //非递归的中序遍历
        public void ninOrder(Node node){
            Stack<Node> s=new Stack<Node>();
            Node n = node;
            while(n != null || !s.isEmpty()){
                if(n != null){
                    s.push(n);
                    n = n.leftNode;
                }else{
                    n = s.pop();
                    System.out.print("->");
                    System.out.print(n.value);
                    n = n.rightNode;
                }
            }
        }
      //非递归后序遍历
        public void npostOrder(Node node){
            Stack<Node> s1=new Stack<Node>();//第一次入栈
            Stack<Node> s2=new Stack<Node>();//第二次入栈
            Node n=node;
            while(!s1.isEmpty() || n!=null){
                if(n != null){
                    s1.push(n);
                    s2.push(n);
                    n=n.rightNode;
                }else{
                    n=s1.pop();
                    n=n.leftNode;
                }
            }
            while(!s2.isEmpty()){
                System.out.print("->");
                System.out.print(s2.pop().value);
            }
        }
        
        //递归前序遍历
        public void preOrder(Node node){
            if(node != null){
                System.out.print("->" + node.value);
                preOrder(node.leftNode);
                preOrder(node.rightNode);
            }
        }
      //中序遍历
        public void inOrder(Node node){
            if(node!=null){
                inOrder(node.leftNode);
                System.out.print("->" + node.value);
                inOrder(node.rightNode);
            }
        }
      //后序遍历
        public void postOrder(Node node){
            if(node!=null){
                postOrder(node.leftNode);
                postOrder(node.rightNode);
                System.out.print("->" + node.value);
            }
        }
    }

     第五招:分治算法

    经典归并排序问题:

    要求:
    对数组进行排序

    思路:
    把数组对半分,把对半分的数组再次对半分,分到最后子数组长度为1的时候开始按照有序规则,合并两个数组,递归返回,最后合并成一个大的有序数组

    //归并排序
        public static int[] mergeSort(int[] arr) {
            if (arr.length < 2) return arr;
            int[] arr1 = Arrays.copyOfRange(arr, 0, arr.length / 2);
            int[] arr2 = Arrays.copyOfRange(arr, arr.length / 2, arr.length);
            arr1 = mergeSort(arr1);
            arr2 = mergeSort(arr2);
            return combine(arr1, arr2);
        }
        //合并函数
        private static int[] combine(int[] arr1, int[] arr2) {
            int[] arr = new int[arr1.length + arr2.length];
            for (int i = 0, j = 0, k = 0; k < arr.length; k++) {
                int temp;
                if (arr1.length <= i) temp = arr2[j++];
                else if (arr2.length <= j) temp = arr1[i++];
                else if (arr1[i] < arr2[j]) temp = arr1[i++];
                else temp = arr2[j++];
                arr[k] = temp;
            }
            return arr;
        }
  • 相关阅读:
    条件极值(1):隐函数极值问题
    从隐函数存在定理到隐函数定理
    吐槽教科书:不先行解释表达偏导数的符号
    8237dma的四种传送方式简介
    多线程中wait和notify的理解与使用
    ★三个和尚与机构臃肿的故事
    ★三个和尚与机构臃肿的故事
    常用的组播保留地址列表
    常用的组播保留地址列表
    谈谈IT界8大恐怖预言!
  • 原文地址:https://www.cnblogs.com/jiangwangxiang/p/12764567.html
Copyright © 2011-2022 走看看