算法-1

算法

数据结构

队列(Queue)

栈(Stack)

树(Tree)

遍历

前序遍历 PreOrderTraversal
- 根左右 - 树状结构展示(注意左右子树的顺序) 中序遍历 InorderTraversal - 左根右 - 二叉搜索树的中序遍历按升序或降序处理节点 后序遍历 postOrderTraversal
- 左右根 - 适用于一些先子后父的操作 层次遍历
- 层级遍历 - 计算二叉树的高度 - 判断是否为完全二叉树

二叉搜索树

  • 任意一个节点的值都大于左子树所有结点的值
  • 任意一个节点的值都小于右子树所有节点的值
  • 他的左右子树也是一颗二叉搜索树
  • 二叉搜索树可以大大提高搜索数据的效率
  • 元素必须剧有可比较性

接口设计

int size() //元素的数量
boolean isEmpty() //是否为空
void clear() //清空所有元素
void add(E element) //添加元素
void remove(E element) //删除元素
boolean contains(E element )//是否包含元素

  • 元素没有索引的概念

前驱节点

  • 中序遍历的前一个节点

后继节点

  • 中序遍历的后一个节点
二叉树(BinaryTree)
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
package notes.Java.JavaLearning_Advanced.Tree;

import notes.Java.JavaLearning_Advanced.Tree.Util.TreePrinter;

import java.util.LinkedList;
import java.util.Queue;

/**
 * @Description:
 * @author: Anhlaidh
 * @date: 2020/4/5 0005 22:44
 */
public class BinaryTree<E> {
    protected int size;
    Node<E> root;
    public Node<E> getRoot() {
        return root;
    }
    public int size() {
        return 0;
    }
    public boolean isEmpty() {
        return size == 0;
    }
    public void clear() {
        size = 0;
        root = null;

    }
    /*
     * 中序遍历
     * 左根右
     * 因为是二叉搜索树,所以中序遍历为有序
     * */
    public void inOrderTraversal(Visitor<E> visitor) {
        inOrderTraversal(root,visitor);
    }
    private void inOrderTraversal(Node<E> node,Visitor<E> visitor) {
        if (visitor==null||node==null) {
return;}
        inOrderTraversal(node.left,visitor);
        visitor.visit(node.element);
        inOrderTraversal(node.right,visitor);
    }
    /*
     * 前序遍历
     * 根左右
     * */
    public void preOrderTraversal(Visitor<E> visitor) {
        preOrderTraversal(root,visitor);
    }
    private void preOrderTraversal(Node<E> node,Visitor<E> visitor) {
        if (visitor==null||node==null) {
return;}
        visitor.visit(node.element);
        preOrderTraversal(node.left,visitor);
        preOrderTraversal(node.right,visitor);
    }
    /*
     * 后序遍历
     * 左右根
     * */
    public void postOderTraversal(Visitor<E> visitor) {
        postOderTraversal(root,visitor);
    }
    private void postOderTraversal(Node<E> node,Visitor<E> visitor) {
        if (visitor==null||node==null) {
return;}
        postOderTraversal(node.left,visitor);
        postOderTraversal(node.right,visitor);
        visitor.visit(node.element);
    }
    /*
     * 层序遍历
     *
     * */
    public void levelOrderTraversal(Visitor visitor) {
        if (root==null) {
return;}
        Queue<Node<E>> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            Node<E> node = queue.poll();
            visitor.visit(node.element);
            if (node.left != null) {
                queue.offer(node.left);
            }
            if (node.right != null) {
                queue.offer(node.right);
            }

        }
    }
    private Node<E> predecessor(Node<E> node) {
        if (node==null) {
return null;}
        //前驱节点在左子树中
        Node<E> p = node.left;
        if (p != null) {
            while (p.right != null) {
                p = p.right;
            }
            return p;
        }
        //从父节点,祖父节点中寻找前驱节点
        while (node.parent != null && node == node.parent.left) {
            node = node.parent;
        }
        return node.parent;
    }
    protected Node<E> successor(Node<E> node) {
        if (node==null) {
return null;}
        //前驱节点在左子树中
        Node<E> p = node.right;
        if (p != null) {
            while (p.left != null) {
                p = p.left;
            }
            return p;
        }
        //从父节点,祖父节点中寻找前驱节点
        while (node.parent != null && node == node.parent.right) {
            node = node.parent;
        }
        return node.parent;
    }

    /*
     *
     * 计算高度
     * 递归
     * */
    public int height() {
        return height(root);
    }
    private int height(Node<E> node) {
        if (node == null) {
            return 0;
        }
        return 1 + Math.max(height(node.left), height(node.right));

    }
    public boolean isComplete() {
        if (root==null) {
return false;}
        Queue<Node<E>> queue = new LinkedList<>();
        queue.add(root);
        boolean leaf = false;
        while (!queue.isEmpty()) {
            Node<E> node = queue.poll();
            if (leaf && !node.isLeaf()) {
                return false;
            }
            if (node.left != null) {
                queue.offer(node.left);
            } else if (node.right != null) {
                return false;
            }
            if (node.right != null) {
                queue.offer(node.right);
            } else {
                leaf = true;
            }

        }
        return true;
    }
    protected static class Node<E> implements TreePrinter.PrintableNode {
        E element;
        Node<E> left;
        Node<E> right;
        Node<E> parent;

        public Node(E element, Node<E> parent) {
            this.element = element;
            this.parent = parent;
        }

        @Override
        public String toString() {
            if (parent==null) {
return element+"";}
            return element + "_P(" + parent.element + ")";
        }

        public boolean isLeaf() {
            return left == null && right == null;
        }

        public boolean hasTwoChildren() {
            return left != null && right != null;
        }

        public boolean isLeftChild() {
            return parent != null && this == parent.left;
        }
        public boolean isRightChild() {
            return parent != null && this == parent.right;
        }

        @Override
        public TreePrinter.PrintableNode getLeft() {
            return left;
        }

        @Override
        public TreePrinter.PrintableNode getRight() {
            return right;
        }

        @Override
        public String getText() {
            return element.toString();
        }


    }
    public interface Visitor<E> {
        void visit(E element);
    }

    protected Node<E> createNode(E element, Node<E> parent) {
        return new Node<>(element, parent);
    }
}
BST
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package notes.Java.JavaLearning_Advanced.Tree;

import java.util.Comparator;

/**
 * @Description:
 * @author: Anhlaidh
 * @date: 2020/4/3 0003 21:19
 */
public class BST<E> extends BinaryTree implements IBinarySearchTree<E>{
    Comparator<E> comparator;


    public BST(Comparator<E> comparator) {
        this.comparator = comparator;
    }

    public BST() {
        comparator = null;
    }


    private void elementNotNullCheck(E element) {
        if (element == null) {
            throw new IllegalArgumentException("element must not be null");
        }
    }

    public void add(E element) {
        if (root == null) {//添加第一个节点
            root = createNode(element, null);
            size++;
            afterAdd(root);
            return;
        }
        //添加的不是第一个节点
        //找到父节点
        Node<E> parent = null;
        Node<E> node = root;
        int cmp = 0;
        while (node != null) {
            cmp = compare(element, node.element);
            parent = node;
            if (cmp > 0) {
                node = node.right;
            } else if (cmp < 0) {
                node = node.left;
            } else {
                node.element = element;
                return;//两个数字相同时
            }
        }
        //看看插入到父节点的哪个位置
        Node<E> newNode = createNode(element, parent);
        if (cmp > 0) {
            parent.right = newNode;
        } else {
            parent.left = newNode;
        }
        size++;
        afterAdd(newNode);

    }

    protected void afterAdd(Node<E> node) { }

    public void remove(E element) {
        remove(node(element));

    }

    private void remove(Node<E> node) {
        if (node==null) {
return;}
        size--;
        //度为2的节点
        if (node.hasTwoChildren()) {
         //找到后继节点
            Node<E> p = successor(node);
            //用后继节点覆盖度为2的节点的值
            node.element = p.element;
            //删除后继节点
            node = p;//TODO 我认为不是很妥

        }
        //删除node节点(node的度必然是0或1)
        Node<E> replacement = node.left != null ? node.left : node.right;
        //node是度为1 的节点
        if (replacement != null) {
            //更改parent
            replacement.parent = node.parent;
            //更改parent的left、right指向
            if (node.parent != null) {
                root = replacement;
            } else if (node == node.parent.left) {
                node.parent.left = replacement;
            } else {// node = node.parent.right
                node.parent.right = replacement;
            }
        } else if (node.parent == null) {//node是叶子节点并且是根节点
            root = null;
        } else {//node是叶子节点,但不是根节点
            if (node == node.parent.left) {
                node.parent.left = null;
            } else {
                node.parent.right = null;
            }

        }

    }

    private Node<E> node(E element) {
        Node<E> p = root;

        while (p != null) {
            int cmp = compare(element, p.element);
            if (cmp < 0) {
                p = p.left;
            }
            if (cmp==0) {
return p;}
            if (cmp > 0) {
                p = p.right;
            }
        }
        return null;
    }

    public boolean contains(E element) {
        return node(element) != null;
    }

    private int compare(E e1, E e2) {
        if (comparator != null) {
           return comparator.compare(e1, e2);
        }
        return ((Comparable<E>) e1).compareTo(e2);
    }


}
AVL
  • 平衡因子(Balance Factor):某节点的左右子树高度
  • AVL树的特点
    • 每个节点的平衡因子只可能是1、0、-1(绝对值<=1,如果超过1,称之为 “失衡”)
    • 每个节点的左右子树高度差不超过1
    • 搜索添加删除的时间复杂度是O(Logn)
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package notes.Java.JavaLearning_Advanced.Tree;

import java.util.Comparator;

/**
 * @Description:
 * @author: Anhlaidh
 * @date: 2020/4/5 0005 23:07
 */
public class AVLTree<E> extends BST<E> {
    public AVLTree(Comparator<E> comparator) {
        super(comparator);
    }

    public AVLTree() {
        this(null);
    }

    @Override
    protected void afterAdd(Node<E> node) {
        do {
            if (isBalanced(node)) {
                //更新高度
                updateHeight(node);
            } else {
                //恢复平衡
                reBalance(node);
                //整棵树恢复平衡
                break;
            }
        } while ((node = node.parent) != null);

    }

    private void reBalance(Node<E> grand) {
        Node<E> parent = ((AVLNode<E>) grand).tallerChild();
        Node<E> node = ((AVLNode) parent).tallerChild();
        if (parent.isLeftChild()) {
            if (node.isLeftChild()) {//LL
                rotateRight(grand);
            } else {//LR
                rotateLeft(parent);
                rotateRight(grand);
            }
        } else {
            if (node.isLeftChild()) {//RL
                rotateRight(parent);
                rotateLeft(grand);
            } else {//RR
                rotateLeft(grand);

            }
        }


    }

    private void rotateLeft(Node<E> grand) {
        Node<E> parent = grand.right;
        Node<E> child = parent.left;
        grand.right = child;
        parent.left = grand;
        afterRotate(grand, parent, child);
    }

    private void rotateRight(Node<E> grand) {
        Node<E> parent = grand.left;
        Node<E> child = parent.right;
        grand.left = child;
        parent.right = grand;
        afterRotate(grand, parent, child);

    }

    private void afterRotate(Node<E> grand, Node<E> parent, Node<E> child) {

        parent.parent = grand.parent;

        // 让parent成为子树的根节点
        if (grand.isLeftChild()) {
            grand.parent.left = parent;
        } else if (grand.isRightChild()) {
            grand.parent.right = parent;
        }else {
            root = parent;
        }

        if (child != null) {
            child.parent = grand;
        }
        grand.parent = parent;
        updateHeight(grand);
        updateHeight(parent);

    }

    class AVLNode<E> extends Node<E> {
        int height;

        public AVLNode(E element, Node<E> parent) {
            super(element, parent);
        }

        public int balanceFactor() {
            int leftHeight = left==null?0:((AVLNode<E>)left).height;
            int rightHeight = right == null ? 0 : ((AVLNode<E>) right).height;
            return leftHeight - rightHeight;
        }
        public void updateHeight() {
            int leftHeight = left == null ? 0 : ((AVLNode<E>) left).height;
            int rightHeight = right == null ? 0 : ((AVLNode<E>) right).height;
            height = 1 + Math.max(leftHeight, rightHeight);
        }

        public Node<E> tallerChild() {
            int leftHeight = left==null?0:((AVLNode<E>)left).height;
            int rightHeight = right == null ? 0 : ((AVLNode<E>) right).height;
            if (leftHeight > rightHeight) {
return left;}
            if (leftHeight < rightHeight)  {
return right;}
            return isLeftChild() ? left : right;

        }
    }

    private boolean isBalanced(Node<E> node) {
        return Math.abs(((AVLNode<E>) node).balanceFactor()) <= 1;
    }

    private void updateHeight(Node<E> node) {
        ((AVLNode<E>) node).updateHeight();
    }



    @Override
    protected Node createNode(Object element, Node parent) {
        return new AVLNode(element, parent);
    }
}
红黑树

图(Map)

排序

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
package HomeWork.sort;

import java.util.*;

/**
 * @Description:
 * @author: Anhlaidh
 * @date: 2020/3/13 0013 15:36
 */
public class SortImpl implements ISort {


    /**
     * 快速排序  O(nLog2n)
     * 一分为三,第一个数字为mid,分成比mid小,比mid大两个数组
     * 可知左边的一定比mid小,右边的一定比mid大
     * 递归拆分,合并即可获得有序数组
     * @param array 数组
     * @return 有序数组
     */
    @Override
    public int[] QuickSort(int[] array) {
        if (array.length<=1) {
return array;}
        int mid = array[0];
        int left=1;
        int current=0;
        int right=array.length-1;
       while (left!=right){
           while (left!=right){
               if (array[right]>=mid) {
right--;}else {
                   array[current] = array[right];
                   current = right;
                   right--;
                   break;
               }
           }
          while (left!=right){

              if (array[left]<mid) {
left++;}else {
                  array[current] = array[left];
                  current = left;
                  left++;
                  break;
              }
          }

       }
        int[] l = Arrays.copyOfRange(array, 0, current);
        int[] r = Arrays.copyOfRange(array, current + 1, array.length);
        int[] l_sort = QuickSort(l);
        int[] r_sort = QuickSort(r);
        array[current] = mid;
        System.arraycopy(l_sort,0,array,0,l_sort.length);
        System.arraycopy(r_sort,0,array,current+1,r_sort.length);
        return array;

    }

    /**
     * 归并排序O(nLog2n)
     * 将数组一分为二一分为二,递归拆分成只有一个数字
     * 根据大小,来组合成有序数组
     * @param array 无序数组
     */

    @Override
    public void MergeSort(int[] array) {
        int mid = array.length/2;
        int[] left = null;
        int[] right=null;
        if (array.length>1){
            //TODO 分成两个数组
            left = Arrays.copyOfRange(array, 0, mid);
             right = Arrays.copyOfRange(array, mid , array.length);
            MergeSort(left);
            MergeSort(right);
        }
        Merge(array,left,right);

    }

    private void Merge(int[] array, int[] left, int[] right) {
        if (left==null||right==null) {
array=array;}else {
           int l=0;
           int r=0;
           int i=0;
           while (i<array.length){
               if (left[l]<right[r]){
                   array[i] = left[l];
                   l++;
                   i++;
                   if (l>=left.length){
                       while (r<right.length){
                           array[i] = right[r];
                           r++;
                           i++;
                       }
                   }
               }
               else{
                   array[i] = right[r];
                   r++;
                   i++;
                   if (r>=right.length){
                       while (l<left.length){
                           array[i] = left[l];
                           i++;
                           l++;
                       }

                   }

               }
           }
        }
    }

    /**
     * 冒泡排序O(n2)
     * 依次比较,当前数字大于比较数字则交换,否则不变,将大数冒到最右
     * 循环冒泡,得到有序数组
     * @param array 无序数组
     */
    @Override
    public void BubbleSort(int[] array) {
        for (int j = array.length; j > 0; j--) {
            for (int i = 0; i < j - 1; i++) {
                if (array[i] > array[i + 1]) {
                    int temp = array[i];
                    array[i] = array[i + 1];
                    array[i + 1] = temp;
                }
            }
        }
    }

    /**
     * 选择排序O(n2)
     * 遍历数组,找到最小值,与array[i]交换,以此类推
     * @param array
     */
    @Override
    public void SelectSort(int[] array) {
        for (int i =0;i<array.length;i++){
            int min=i;
            for (int j=i ;j <array.length;j++){

                if (array[j] <array[min]){
                    min = j;
                }
            }
            if (min!=i){
                int temp = array[min];
                array[min] = array[i];
                array[i] = temp;
            }

        }

    }

    /**
     * 直接插入排序O(n2)
     * 依次遍历剩余数组,与当前尾节点比较,决定插入位置,循环插入
     * @param array
     */
    @Override
    public void InsertionSort(int[] array) {
        int index = 0;//当前排好序的尾节点


        while (index < array.length) {
            int minIndex = index; // 遍历列表最小值坐标
            for (int i = index; i < array.length; i++) {
                minIndex = array[i] < array[minIndex] ? i : minIndex;
                //找到最小值并记录坐标

            }
            {
                int temp = array[minIndex];
                array[minIndex] = array[index];
                array[index] = temp;
            }
            //交换位置
            for (int i = index-1; i >= 0; i--) {
                if (array[i] >= array[i + 1]) {
                    int temp = array[i];
                    array[i] = array[i + 1];
                    array[i + 1] = temp;
                }
            }
            index++;
        }
    }
}

分治

分而治之

动态规划 O(n*m)

题目特点

  1. 计数
    • 有多少种方式走到右下角
    • 有多少种方法选出k个数使得和是sum
  2. 求最大最小值
    • 从左上角走到右小角路径的最大数字和
    • 最长上升子序列长度
  3. 求存在性
    • 取石子游戏,先手是否必胜
    • 能不能选出k个数使得和是sum

解题步骤

  1. 确定状态

    • 知到f[i][j]代表什么
    • 两个意识
      • 最后一步(最优策略中使用的最后一枚硬币a[k])
      • 化成子问题(最少的硬币拼出更小的面值27-a[k])
  2. 转移方程

    • f[X] = min{f[X-2]+1,f[X-5]+1,f[X-7]+1}
  3. 初始条件和边界情况

    • 初始条件:用转移方程算不出来,却又理所应当的值,需要手工定义(F[0]=0)
    • 设定边界,例如不存在小于零的可能,定义小于零为正无穷(不要数组越界)
  4. 计算顺序

    • 当我们计算到F[X]时,F[X-2],f[X-5],F[X-7]都已经得到结果了
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
    public int coinChange(int[] coins, int amount) {
        int n = coins.length;
        int M = amount + 1;
        int[] f = new int[M];
//初始化        
        f[0] = 0;
        for (int i = 1; i < M; i++) {
            f[i] = Integer.MAX_VALUE;
            for (int j = 0; j < n; j++) {
                if (i - coins[j] >= 0 && f[i - coins[j]] != Integer.MAX_VALUE) {
//                    转移方程
                    f[i] = Math.min(f[i - coins[j]] + 1, f[i]);
                }
            }
        }
        if (f[amount] == Integer.MAX_VALUE) {
            return -1;
        }
        return f[amount];
    }
}

二维:不同路径

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class q62 {
    public static void main(String[] args) {
        System.out.println(uniquePaths(3, 2));

    }

    public static int uniquePaths(int m, int n) {
        int[][] f = new int[m][n];
        f[0][0] = 0;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (i == 0 || j == 0) {
                    f[i][j] = 1;
                    continue;
                }
                f[i][j] = f[i - 1][j] + f[i][j - 1];

            }
        }
        return f[m - 1][n - 1];

    }
}

动态规划初探

  • 坐标型动态规划
    • 给定坐标,怎么走
    • 给定一个序列或网格
    • 需要找到序列中某个/些子序列或网格中的某条路径
      • 某种性质最大/最小
      • 计数
      • 存在性
    • 动态规划方程f[i]中的下表i表示以a[i]为结尾的满足条件的子序列,f[i][j]中的下表i,j代表以格子(i,j)为结尾的满足条件的路径的性质
      • 最大值/最小值
      • 个数
      • 是否存在
    • 坐标型动态规划的初始条件f[0]就是指以a[0]为结尾的子序列的性质
  • 序列型动态规划 : 前i个…最小/方式数/可行性
    • 在设计动态规划的过程中,发现需要知道油漆钱N-1栋房子的最优策略中,房子N-2的颜色
    • 如果只用f[N-1],将无法区分
    • 解决方法:记录下房子N-2的颜色
      • 在房子N-2是红/蓝/绿的情况下,前N-1栋房子的最小花费
    • 序列+状态
  • 划分型动态规划

优化

  • 空间优化
    • 滚动数组
      • 计算dp[0][0],……dp[0][n-1],计算dp[1][0]…….dp[1][n-1]
      • 计算dp[2][0],……dp[2][n-1],把值写在f[0][0]…….dp[0][n-1]的数组里
      • 同理,dp[3][0],……dp[3][n-1],写在dp[1][0]…….dp[1][n-1]的数组里
      • 最后dp[m-1][n-1]存在dp[0][n-1](或者f[1][n-1]里),直接输出
Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
Built with Hugo
主题 StackJimmy 设计