算法十八招

第一招:动态规划算法

动态规划思想:把问题分解为多个阶段,每个阶段执行决策,记录每一个阶段可达的状态集合(去重后),
基于当前阶段的状态集合,通过决策,推导下一个阶段的状态结婚,动态的往前推进
经典背包问题:有一组不同重量不可分割的物品,需要选择一些装入背包,在满足背包最大重量限制的前提下
,背包中物品的最大重量是多少?
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;
    }

 

posted @ 2020-04-23 23:14  将王相  阅读(266)  评论(0编辑  收藏  举报