【面试现场】如何编程获得最多的年终红包奖?

点击上方"Java学习之道",选择"关注"公众号

每天10:24,干货准时送达!


640?wx_fmt=jpeg


小史是一个应届生,虽然学的是电子专业,但是自己业余时间看了很多互联网与编程方面的书,一心想进BAT互联网公司。

640?wx_fmt=jpeg


今天小史又去了一家互联网小巨头公司面试了。


640?wx_fmt=jpeg


【面试现场】


640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg


小史眉头一皱,发现事情并不简单。


640?wx_fmt=jpeg

题目:在数字矩阵中,从左上角到右下角,每次只能向右或向下,如何规划路径,能获得最大数字总和?


小史开始仔细分析问题,一时间竟想不到很好的方法。


640?wx_fmt=jpeg

小史心中反复默念题目,进行思考。


640?wx_fmt=jpeg

小史仔细回忆起了吕老师教他的华容道搜索算法


640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg


【请教大神】


回到学校,小史把面试情况和吕老师说了一下。


640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

吕老师:红色和蓝色两条路都能到达中间的100这个点,但是很明显,红色的路拿到的奖金更多。所以蓝色的路,后面不管再怎么走,都不可能拿到最大的奖金数了。

640?wx_fmt=jpeg

640?wx_fmt=jpeg

吕老师:假设蓝色路径再往后走出一条绿色路径是最大奖金,那么我把蓝色路径替换成红色路径,红色加绿色得到的奖金就比蓝色加绿色得到的多呀。

640?wx_fmt=jpeg

640?wx_fmt=jpeg


【记忆化搜索】


640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

小史:哦,我明白了,这样我每搜到一个点,都可以和这个数比较,如果比它大,就更新这个数,继续搜,如果比它小,就不搜了,直接剪枝。

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

理解了算法之后,小史的代码写起来也是非常快,不一会儿就写好了:


DeepFirstSearch.java

 
 
import java.util.ArrayList;import java.util.List;/** * @author xiaoshi on 2018/10/20. */public class DeepFirstSearch {    // 定义best(i,j) 和 M N    private int[][] best = null;    private int M = 0;    private int N = 0;    // 定义方向常量    private static final int RIGHT = 1;    private static final int DOWN = 2;    // 当前搜索的方向数组    private List<Integer> curPath = null;    // 记录最大值对应的方向数组    private Integer[] bestPath = null;    // 当前搜索点    private int curX = 0;    private int curY = 0;    // 当前搜索累计值    private int value = 0;    // 记录搜索到的最大值    private int maxValue = 0;    // 往某个方向前进    private void goDir(int dir, int[][] matrix) {        // 前进        if(dir == DOWN) {            curX++;            value += matrix[curX][curY];        } else if(dir == RIGHT) {            curY++;            value += matrix[curX][curY];        }        // 记录方向        curPath.add(dir);    }    // 往某个方向回退    private void goBackDir(int dir, int[][] matrix) {        // 回退        if(dir == DOWN) {            value -= matrix[curX][curY];            curX--;        } else if(dir == RIGHT) {            value -= matrix[curX][curY];            curY--;        }        // 移除方向        curPath.remove(curPath.size() - 1);    }    // 深搜    private void search(int dir, int[][] matrix) {        // 往某方向前进        goDir(dir, matrix);        // 到达终点        if(curX == M - 1 && curY == N - 1) {            if(value > maxValue) {                // 记录最大值和路径                maxValue = value;                bestPath = new Integer[curPath.size()];                curPath.toArray(bestPath);            }        } else if(value <= best[curX][curY]) {            // 不搜索了,等着goBack,剪枝        } else {            // 更新best(i,j),记忆            best[curX][curY] = value;            // 朝下一个方向搜索            if(curX < M - 1) {                search(DOWN, matrix);            }            if(curY < N - 1) {                search(RIGHT, matrix);            }        }        // 往某方向回退        goBackDir(dir, matrix);    }    // 获取最大值    public int getMaxAward(int[][] matrix) {        // 初始化        value = matrix[0][0];        M = matrix.length;        N = matrix[0].length;        best = new int[M][N];        curPath = new ArrayList<Integer>();        // 开始搜索        if(M > 1) {            search(DOWN, matrix);        }        if(N > 1) {            search(RIGHT, matrix);        }        // 最大值        return maxValue;    }    // 打印最佳路径    public void printBestPath() {        // 打印路径        for(int i = 0; i < bestPath.length; i++) {            if(bestPath[i] == RIGHT) {                System.out.print("右 ");            } else {                System.out.print("下 ");            }        }        System.out.println();    }}

/**
 * @author xiaoshi on 2018/10/20.
 */

public class DeepFirstSearch {

    // 定义best(i,j) 和 M N
    private int[][] best = null;
    private int M = 0;
    private int N = 0;

    // 定义方向常量
    private static final int RIGHT = 1;
    private static final int DOWN = 2;
    // 当前搜索的方向数组
    private List<Integer> curPath = null;
    // 记录最大值对应的方向数组
    private Integer[] bestPath = null;

    // 当前搜索点
    private int curX = 0;
    private int curY = 0;
    // 当前搜索累计值
    private int value = 0;
    // 记录搜索到的最大值
    private int maxValue = 0;

    // 往某个方向前进
    private void goDir(int dir, int[][] matrix{
        // 前进
        if(dir == DOWN) {
            curX++;
            value += matrix[curX][curY];
        } else if(dir == RIGHT) {
            curY++;
            value += matrix[curX][curY];
        }
        // 记录方向
        curPath.add(dir);
    }

    // 往某个方向回退
    private void goBackDir(int dir, int[][] matrix{
        // 回退
        if(dir == DOWN) {
            value -= matrix[curX][curY];
            curX--;
        } else if(dir == RIGHT) {
            value -= matrix[curX][curY];
            curY--;
        }
        // 移除方向
        curPath.remove(curPath.size() - 1);
    }

    // 深搜
    private void search(int dir, int[][] matrix{
        // 往某方向前进
        goDir(dir, matrix);
        // 到达终点
        if(curX == M - 1 && curY == N - 1) {
            if(value > maxValue) {
                // 记录最大值和路径
                maxValue = value;
                bestPath = new Integer[curPath.size()];
                curPath.toArray(bestPath);
            }
        } else if(value <= best[curX][curY]) {
            // 不搜索了,等着goBack,剪枝
        } else {
            // 更新best(i,j),记忆
            best[curX][curY] = value;
            // 朝下一个方向搜索
            if(curX < M - 1) {
                search(DOWN, matrix);
            }
            if(curY < N - 1) {
                search(RIGHT, matrix);
            }
        }
        // 往某方向回退
        goBackDir(dir, matrix);
    }

    // 获取最大值
    public int getMaxAward(int[][] matrix{
        // 初始化
        value = matrix[0][0];
        M = matrix.length;
        N = matrix[0].length;
        best = new int[M][N];
        curPath = new ArrayList<Integer>();
        // 开始搜索
        if(M > 1) {
            search(DOWN, matrix);
        }
        if(N > 1) {
            search(RIGHT, matrix);
        }
        // 最大值
        return maxValue;
    }

    // 打印最佳路径
    public void printBestPath({
        // 打印路径
        for(int i = 0; i < bestPath.length; i++) {
            if(bestPath[i] == RIGHT) {
                System.out.print("右 ");
            } else {
                System.out.print("下 ");
            }
        }
        System.out.println();
    }

}

(友情提示:可左右滑动)


Main.java

 
 
/** * @author xiaoshi on 2018/10/20. */public class Main {    public static void main(String[] args) {        int[][] matrix1 = {            {300, 500, 560, 400, 160},            {1000, 100, 200, 340, 690},            {600, 500, 500, 460, 320},            {300, 400, 250, 210, 760}        };        int[][] matrix2 = {            {300, 500, 2560, 400},            {1000, 100, 200, 340},            {600, 500, 500, 460},            {300, 400, 250, 210},            {860, 690, 320, 760}        };        DeepFirstSearch dp = new DeepFirstSearch();        System.out.println(dp.getMaxAward(matrix1));        dp.printBestPath();        System.out.println(dp.getMaxAward(matrix2));        dp.printBestPath();    }}
public class Main {

    public static void main(String[] args{

        int[][] matrix1 = {
            {300500560400160},
            {1000100200340690},
            {600500500460320},
            {300400250210760}
        };

        int[][] matrix2 = {
            {3005002560400},
            {1000100200340},
            {600500500460},
            {300400250210},
            {860690320760}
        };

        DeepFirstSearch dp = new DeepFirstSearch();

        System.out.println(dp.getMaxAward(matrix1));
        dp.printBestPath();

        System.out.println(dp.getMaxAward(matrix2));
        dp.printBestPath();

    }
}

(友情提示:可左右滑动)


运行结果

 
 
4440下 下 右 右 右 右 下 5530右 右 右 下 下 下 下 
5530
右 右 右 下 下 下 下 


【记忆广搜】


640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

吕老师:记忆深搜确实可以剪枝,但是假如有人刻意安排数字,把较小的数都安排在你先搜的路径上,那么你的计算量还是不会减少太多。

640?wx_fmt=jpeg

640?wx_fmt=jpeg

小史:还有这么坏的人呢?不过你这样一说我到想起来,深搜确实缺少一种“全局观”,可能第一条路搜完了,再来看第二条路,发现更好,结果第一条路全白搜了。

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

理解了算法之后,小史的代码写起来也是非常快,不一会儿就写好了:


BreadthFirstSearch.java

 
 
import java.util.ArrayList;import java.util.LinkedList;import java.util.List;/** * @author xiaoshi on 2018/10/20. */public class BreadthFirstSearch {    // 定义 M N    private int M = 0;    private int N = 0;    // 定义方向常量    private static final int RIGHT = 1;    private static final int DOWN = 2;    // 代表广搜的每一步,通过lastItem链起来    private class SearchItem {        private int curX;        private int curY;        private int dir;        // 这里记录 (curX, curY) 路径的最大值,相当于best(i,j)        private int value;        private SearchItem lastItem;        public SearchItem(int curX, int curY, int dir, int value) {            this.curX = curX;            this.curY = curY;            this.dir = dir;            this.value = value;        }    }    // 最终搜到的结果    private SearchItem bestItem = null;    // 广搜的存储队列    private List<SearchItem> statusToSearch = new LinkedList<SearchItem>();    // 替换广搜队列中较小的item,返回值为搜索队列中是否找到相应item    private boolean replaceStatusList(SearchItem newItem) {        // 是否找到        boolean find = false;        // 遍历查找        for(int i=0; i<statusToSearch.size(); i++) {            SearchItem searchItem = statusToSearch.get(i);            // 找到对应item            if(searchItem.curX == newItem.curX && searchItem.curY == searchItem.curY) {                find = true;                // 这里相当于在对比best(i,j)                if(searchItem.value < newItem.value) {                    // 替换成更好的item                    statusToSearch.remove(i);                    statusToSearch.add(i, newItem);                }                break;            }        }        return find;    }    // 广搜    private void search(int[][] matrix) {        // 搜索队列中不为空        while(statusToSearch.size() > 0) {            // 从搜索队列中获取一个item            SearchItem searchItem = statusToSearch.remove(0);            int curX = searchItem.curX;            int curY = searchItem.curY;            int curValue = searchItem.value;            // 如果已经搜到            if(curX == M - 1 && curY == N - 1) {                bestItem = searchItem;            }            // 可往下搜            if(curX < M - 1) {                SearchItem newItem = new SearchItem(curX + 1, curY, DOWN, curValue + matrix[curX + 1][curY]);                newItem.lastItem = searchItem;                // 是否替代                if(!replaceStatusList(newItem)) {                    // 搜索队列中没有找到,则添加                    statusToSearch.add(newItem);                }            }            // 可往右搜            if(curY < N - 1) {                SearchItem newItem = new SearchItem(curX, curY + 1, RIGHT, curValue + matrix[curX][curY + 1]);                newItem.lastItem = searchItem;                // 是否替代                if(!replaceStatusList(newItem)) {                    // 搜索队列中没有找到,则添加                    statusToSearch.add(newItem);                }            }        }    }    // 获取最大值    public int getMaxAward(int[][] matrix) {        // 初始化        M = matrix.length;        N = matrix[0].length;        int value = matrix[0][0];        SearchItem searchItem = new SearchItem(0, 0, 0, value);        statusToSearch.add(searchItem);        // 开始搜索        search(matrix);        // 返回最大值        return bestItem.value;    }    // 打印最佳路径    public void printBestPath() {        List<Integer> dirList = new ArrayList<Integer>();        SearchItem curSearchItem = bestItem;        // 根据lastItem,找到路径        while(null != curSearchItem) {            int dir = curSearchItem.dir;            if(dir == DOWN) {                dirList.add(DOWN);            } else if(dir == RIGHT) {                dirList.add(RIGHT);            }            curSearchItem = curSearchItem.lastItem;        }        // 打印路径        for(int i = dirList.size() - 1; i >= 0; i--) {            if(dirList.get(i) == DOWN) {                System.out.print("下 ");            } else if(dirList.get(i) == RIGHT) {                System.out.print("右 ");            }        }        System.out.println();    }}
import java.util.List;

/**
 * @author xiaoshi on 2018/10/20.
 */

public class BreadthFirstSearch {

    // 定义 M N
    private int M = 0;
    private int N = 0;

    // 定义方向常量
    private static final int RIGHT = 1;
    private static final int DOWN = 2;

    // 代表广搜的每一步,通过lastItem链起来
    private class SearchItem {
        private int curX;
        private int curY;
        private int dir;
        // 这里记录 (curX, curY) 路径的最大值,相当于best(i,j)
        private int value;
        private SearchItem lastItem;
        public SearchItem(int curX, int curY, int dir, int value{
            this.curX = curX;
            this.curY = curY;
            this.dir = dir;
            this.value = value;
        }
    }

    // 最终搜到的结果
    private SearchItem bestItem = null;

    // 广搜的存储队列
    private List<SearchItem> statusToSearch = new LinkedList<SearchItem>();

    // 替换广搜队列中较小的item,返回值为搜索队列中是否找到相应item
    private boolean replaceStatusList(SearchItem newItem{
        // 是否找到
        boolean find = false;
        // 遍历查找
        for(int i=0; i<statusToSearch.size(); i++) {
            SearchItem searchItem = statusToSearch.get(i);
            // 找到对应item
            if(searchItem.curX == newItem.curX && searchItem.curY == searchItem.curY) {
                find = true;
                // 这里相当于在对比best(i,j)
                if(searchItem.value < newItem.value) {
                    // 替换成更好的item
                    statusToSearch.remove(i);
                    statusToSearch.add(i, newItem);
                }
                break;
            }
        }
        return find;
    }

    // 广搜
    private void search(int[][] matrix{

        // 搜索队列中不为空
        while(statusToSearch.size() > 0) {
            // 从搜索队列中获取一个item
            SearchItem searchItem = statusToSearch.remove(0);
            int curX = searchItem.curX;
            int curY = searchItem.curY;
            int curValue = searchItem.value;
            // 如果已经搜到
            if(curX == M - 1 && curY == N - 1) {
                bestItem = searchItem;
            }
            // 可往下搜
            if(curX < M - 1) {
                SearchItem newItem = new SearchItem(curX + 1, curY, DOWN, curValue + matrix[curX + 1][curY]);
                newItem.lastItem = searchItem;
                // 是否替代
                if(!replaceStatusList(newItem)) {
                    // 搜索队列中没有找到,则添加
                    statusToSearch.add(newItem);
                }
            }
            // 可往右搜
            if(curY < N - 1) {
                SearchItem newItem = new SearchItem(curX, curY + 1, RIGHT, curValue + matrix[curX][curY + 1]);
                newItem.lastItem = searchItem;
                // 是否替代
                if(!replaceStatusList(newItem)) {
                    // 搜索队列中没有找到,则添加
                    statusToSearch.add(newItem);
                }
            }
        }
    }

    // 获取最大值
    public int getMaxAward(int[][] matrix{
        // 初始化
        M = matrix.length;
        N = matrix[0].length;
        int value = matrix[0][0];
        SearchItem searchItem = new SearchItem(000value);
        statusToSearch.add(searchItem);
        // 开始搜索
        search(matrix);
        // 返回最大值
        return bestItem.value;
    }

    // 打印最佳路径
    public void printBestPath({
        List<Integer> dirList = new ArrayList<Integer>();
        SearchItem curSearchItem = bestItem;
        // 根据lastItem,找到路径
        while(null != curSearchItem) {
            int dir = curSearchItem.dir;
            if(dir == DOWN) {
                dirList.add(DOWN);
            } else if(dir == RIGHT) {
                dirList.add(RIGHT);
            }
            curSearchItem = curSearchItem.lastItem;
        }
        // 打印路径
        for(int i = dirList.size() - 1; i >= 0; i--) {
            if(dirList.get(i) == DOWN) {
                System.out.print("下 ");
            } else if(dirList.get(i) == RIGHT) {
                System.out.print("右 ");
            }
        }
        System.out.println();
    }

}

(友情提示:可左右滑动)


Main.java

 
 
/** * @author xiaoshi on 2018/10/20. */public class Main {    public static void main(String[] args) {        int[][] matrix1 = {            {300, 500, 560, 400, 160},            {1000, 100, 200, 340, 690},            {600, 500, 500, 460, 320},            {300, 400, 250, 210, 760}        };        int[][] matrix2 = {            {300, 500, 2560, 400},            {1000, 100, 200, 340},            {600, 500, 500, 460},            {300, 400, 250, 210},            {860, 690, 320, 760}        };        BreadthFirstSearch dp = new BreadthFirstSearch();        System.out.println(dp.getMaxAward(matrix1));        dp.printBestPath();        System.out.println(dp.getMaxAward(matrix2));        dp.printBestPath();    }}
public class Main {

    public static void main(String[] args{

        int[][] matrix1 = {
            {300500560400160},
            {1000100200340690},
            {600500500460320},
            {300400250210760}
        };

        int[][] matrix2 = {
            {3005002560400},
            {1000100200340},
            {600500500460},
            {300400250210},
            {860690320760}
        };

        BreadthFirstSearch dp = new BreadthFirstSearch();

        System.out.println(dp.getMaxAward(matrix1));
        dp.printBestPath();

        System.out.println(dp.getMaxAward(matrix2));
        dp.printBestPath();

    }
}

(友情提示:可左右滑动)


运行结果

 
 
4440下 下 右 右 右 右 下 5530右 右 右 下 下 下 下 
5530
右 右 右 下 下 下 下 


【动态规划】


640?wx_fmt=jpeg

吕老师:小史,代码写得不错,咱们再来看看广搜的过程,其实就是在搜索的过程中从左上到右下计算出了best(i,j),所以为啥我们不能直接算出best(i,j)呢?

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

理解了算法之后,小史的代码写起来也是非常快,不一会儿就写好了:


DynamicProgramming.java

 
 
import java.util.ArrayList;import java.util.List;/** * @author xiaoshi on 2018/10/20. */public class DynamicProgramming {    // 定义best(i,j) 和 M N    private int[][] best = null;    private int M = 0;    private int N = 0;    // 定义方向常量    private static final int RIGHT = 1;    private static final int DOWN = 2;    // 存储最好路径    private List<Integer> bestPath = null;    // 计算best(i,j)    private void calcDp(int[][] matrix) {        // 初始化        M = matrix.length;        N = matrix[0].length;        best = new int[M][N];        // 计算        for(int i = 0; i < M; i++) {            for(int j = 0; j < N; j++) {                // 边界                if(i == 0 && j == 0) {                    best[i][j] = matrix[i][j];                } else if(i == 0) {                    best[i][j] = best[i][j - 1] + matrix[i][j];                } else if(j == 0) {                    best[i][j] = best[i - 1][j] + matrix[i][j];                } else {                    // 状态转移                    best[i][j] = Math.max(best[i - 1][j], best[i][j - 1]) + matrix[i][j];                }            }        }    }    // 获取最大值    public int getMaxAward(int[][] matrix) {        // 计算状态        calcDp(matrix);        // 计算最佳路径        calcBestPath();        // 返回最大值        return best[matrix.length - 1][matrix[0].length - 1];    }    // 计算最佳路径,从后往前    private void calcBestPath() {        bestPath = new ArrayList<Integer>();        // 总共走 M + N - 2 步        int curX = M - 1;        int curY = N - 1;        // 根据best(i,j)计算最佳路径        for(int i = 0; i < M + N - 2; i++) {            if(curX == 0) {                curY--;                bestPath.add(RIGHT);            } else if(curY == 0) {                curX--;                bestPath.add(DOWN);            } else {                if(best[curX - 1][curY] > best[curX][curY - 1]) {                    curX--;                    bestPath.add(DOWN);                } else {                    curY--;                    bestPath.add(RIGHT);                }            }        }    }    // 打印最佳路径    public void printBestPath() {        // 倒序打印        for(int i = bestPath.size() - 1; i >= 0; i--) {            if(bestPath.get(i) == RIGHT) {                System.out.print("右 ");            } else {                System.out.print("下 ");            }        }        System.out.println();    }}

/**
 * @author xiaoshi on 2018/10/20.
 */

public class DynamicProgramming {

    // 定义best(i,j) 和 M N
    private int[][] best = null;
    private int M = 0;
    private int N = 0;

    // 定义方向常量
    private static final int RIGHT = 1;
    private static final int DOWN = 2;
    // 存储最好路径
    private List<Integer> bestPath = null;

    // 计算best(i,j)
    private void calcDp(int[][] matrix{
        // 初始化
        M = matrix.length;
        N = matrix[0].length;
        best = new int[M][N];
        // 计算
        for(int i = 0; i < M; i++) {
            for(int j = 0; j < N; j++) {
                // 边界
                if(i == 0 && j == 0) {
                    best[i][j] = matrix[i][j];
                } else if(i == 0) {
                    best[i][j] = best[i][j - 1] + matrix[i][j];
                } else if(j == 0) {
                    best[i][j] = best[i - 1][j] + matrix[i][j];
                } else {
                    // 状态转移
                    best[i][j] = Math.max(best[i - 1][j], best[i][j - 1]) + matrix[i][j];
                }
            }
        }
    }

    // 获取最大值
    public int getMaxAward(int[][] matrix{
        // 计算状态
        calcDp(matrix);
        // 计算最佳路径
        calcBestPath();
        // 返回最大值
        return best[matrix.length - 1][matrix[0].length - 1];
    }

    // 计算最佳路径,从后往前
    private void calcBestPath({
        bestPath = new ArrayList<Integer>();
        // 总共走 M + N - 2 步
        int curX = M - 1;
        int curY = N - 1;
        // 根据best(i,j)计算最佳路径
        for(int i = 0; i < M + N - 2; i++) {
            if(curX == 0) {
                curY--;
                bestPath.add(RIGHT);
            } else if(curY == 0) {
                curX--;
                bestPath.add(DOWN);
            } else {
                if(best[curX - 1][curY] > best[curX][curY - 1]) {
                    curX--;
                    bestPath.add(DOWN);
                } else {
                    curY--;
                    bestPath.add(RIGHT);
                }
            }
        }
    }

    // 打印最佳路径
    public void printBestPath({
        // 倒序打印
        for(int i = bestPath.size() - 1; i >= 0; i--) {
            if(bestPath.get(i) == RIGHT) {
                System.out.print("右 ");
            } else {
                System.out.print("下 ");
            }
        }
        System.out.println();
    }

}

(友情提示:可左右滑动)


Main.java

 
 
/** * @author xiaoshi on 2018/10/20. */public class Main {    public static void main(String[] args) {        int[][] matrix1 = {            {300, 500, 560, 400, 160},            {1000, 100, 200, 340, 690},            {600, 500, 500, 460, 320},            {300, 400, 250, 210, 760}        };        int[][] matrix2 = {            {300, 500, 2560, 400},            {1000, 100, 200, 340},            {600, 500, 500, 460},            {300, 400, 250, 210},            {860, 690, 320, 760}        };        DynamicProgramming dp = new DynamicProgramming();        System.out.println(dp.getMaxAward(matrix1));        dp.printBestPath();        System.out.println(dp.getMaxAward(matrix2));        dp.printBestPath();    }}
public class Main {

    public static void main(String[] args{

        int[][] matrix1 = {
            {300500560400160},
            {1000100200340690},
            {600500500460320},
            {300400250210760}
        };

        int[][] matrix2 = {
            {3005002560400},
            {1000100200340},
            {600500500460},
            {300400250210},
            {860690320760}
        };

        DynamicProgramming dp = new DynamicProgramming();

        System.out.println(dp.getMaxAward(matrix1));
        dp.printBestPath();

        System.out.println(dp.getMaxAward(matrix2));
        dp.printBestPath();

    }
}

(友情提示:可左右滑动)


运行结果

 
 
4440下 下 右 右 右 右 下 5530右 右 右 下 下 下 下 
5530
右 右 右 下 下 下 下 


【动态规划解析】


640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

吕老师:状态的定义要满足几个点,第一,问题的答案是某种状态,或者可由状态进行推导。第二,当前状态可以由之前的状态推导而来。

640?wx_fmt=jpeg

【状态压缩】


640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

小史:哦,我知道了,这道题,如果按照斜线方向来计算,只需要保留一条斜线的状态,就能计算出下一条斜线。所以之前的状态就不需要保留了。

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg


理解了算法之后,小史的代码写起来也是非常快,不一会儿就写好了:


DpCompressed.java

 
 
/** * @author xiaoshi on 2018/10/20. */public class DpCompressed {    // 定义best(i) 和 M N    private int[][] best = null;    private int M = 0;    private int N = 0;    // 计算best(i)    private void calcDp(int[][] matrix) {        // 初始化        M = matrix.length;        N = matrix[0].length;        int minMN = Math.min(M, N);        int maxMN = Math.max(M, N);        // best只需要M和N的最小值长度就行        best = new int[2][minMN];        // 需要计算 M+N-1 条斜线        for(int i = 0; i < M + N - 1; i++) {            // 第 i 条斜线的起始x坐标            int startX = 0;            // 第 i 条斜线的起始y坐标            int startY = i;            // 第 i 条斜线的数字个数            int number = i + 1;            if(i >= N) {                startX = i + 1 - N;                startY = N - 1;            }            if(i >= minMN) {                number = minMN;            }            if(i >= maxMN) {                number = M + N - i - 1;            }            // 第 i 条斜线上的 number 个数            for(int j = 0; j < number; j++) {                // 起始点                if(i == 0 && j == 0) {                    best[1][j] = matrix[startX + j][startY - j];                } else {                    if (i < N) {                        // 前半部分                        if (j == 0) {                            // 上边界                            best[1][j] = best[0][j] + matrix[startX + j][startY - j];                        } else if (j == number - 1) {                            // 左边界                            best[1][j] = best[0][j-1] + matrix[startX + j][startY - j];                        } else {                            // 状态转移                            best[1][j] = Math.max(best[0][j], best[0][j-1]) + matrix[startX + j][startY - j];                        }                    } else {                        // 后半部分                        if(i < M && j == number - 1) {                            // 左边界                            best[1][j] = best[0][j] + matrix[startX + j][startY - j];                        } else {                            // 状态转移                            best[1][j] = Math.max(best[0][j], best[0][j+1]) + matrix[startX + j][startY - j];                        }                    }                }            }            // 将best[1]上的状态拷贝到best[0]            for(int j = 0; j < number; j++) {                best[0][j] = best[1][j];            }        }    }    // 获取最大值    public int getMaxAward(int[][] matrix) {        calcDp(matrix);        return best[0][0];    }}
public class DpCompressed {

    // 定义best(i) 和 M N
    private int[][] best = null;
    private int M = 0;
    private int N = 0;

    // 计算best(i)
    private void calcDp(int[][] matrix{
        // 初始化
        M = matrix.length;
        N = matrix[0].length;
        int minMN = Math.min(M, N);
        int maxMN = Math.max(M, N);
        // best只需要M和N的最小值长度就行
        best = new int[2][minMN];
        // 需要计算 M+N-1 条斜线
        for(int i = 0; i < M + N - 1; i++) {
            // 第 i 条斜线的起始x坐标
            int startX = 0;
            // 第 i 条斜线的起始y坐标
            int startY = i;
            // 第 i 条斜线的数字个数
            int number = i + 1;
            if(i >= N) {
                startX = i + 1 - N;
                startY = N - 1;
            }
            if(i >= minMN) {
                number = minMN;
            }
            if(i >= maxMN) {
                number = M + N - i - 1;
            }
            // 第 i 条斜线上的 number 个数
            for(int j = 0; j < number; j++) {
                // 起始点
                if(i == 0 && j == 0) {
                    best[1][j] = matrix[startX + j][startY - j];
                } else {
                    if (i < N) {
                        // 前半部分
                        if (j == 0) {
                            // 上边界
                            best[1][j] = best[0][j] + matrix[startX + j][startY - j];
                        } else if (j == number - 1) {
                            // 左边界
                            best[1][j] = best[0][j-1] + matrix[startX + j][startY - j];
                        } else {
                            // 状态转移
                            best[1][j] = Math.max(best[0][j], best[0][j-1]) + matrix[startX + j][startY - j];
                        }
                    } else {
                        // 后半部分
                        if(i < M && j == number - 1) {
                            // 左边界
                            best[1][j] = best[0][j] + matrix[startX + j][startY - j];
                        } else {
                            // 状态转移
                            best[1][j] = Math.max(best[0][j], best[0][j+1]) + matrix[startX + j][startY - j];
                        }
                    }
                }
            }
            // 将best[1]上的状态拷贝到best[0]
            for(int j = 0; j < number; j++) {
                best[0][j] = best[1][j];
            }
        }
    }

    // 获取最大值
    public int getMaxAward(int[][] matrix{
        calcDp(matrix);
        return best[0][0];
    }

}

(友情提示:可左右滑动)


Main.java

 
 
/** * @author xiaoshi on 2018/10/20. */public class Main {    public static void main(String[] args) {        int[][] matrix1 = {            {300, 500, 560, 400, 160},            {1000, 100, 200, 340, 690},            {600, 500, 500, 460, 320},            {300, 400, 250, 210, 760}        };        int[][] matrix2 = {            {300, 500, 2560, 400},            {1000, 100, 200, 340},            {600, 500, 500, 460},            {300, 400, 250, 210},            {860, 690, 320, 760}        };        DpCompressed dp = new DpCompressed();        System.out.println(dp.getMaxAward(matrix1));        System.out.println(dp.getMaxAward(matrix2));    }}
public class Main {

    public static void main(String[] args{

        int[][] matrix1 = {
            {300500560400160},
            {1000100200340690},
            {600500500460320},
            {300400250210760}
        };

        int[][] matrix2 = {
            {3005002560400},
            {1000100200340},
            {600500500460},
            {300400250210},
            {860690320760}
        };

        DpCompressed dp = new DpCompressed();

        System.out.println(dp.getMaxAward(matrix1));

        System.out.println(dp.getMaxAward(matrix2));

    }
}

(友情提示:可左右滑动)


运行结果

 
 
44405530


640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg



PS:这次这篇花费了两周时间。如果你看到了这里,并且有所收获的话,可以动动手指转发一下哦,小史和吕老师都会感谢你。




面试现场是公众号【互联网侦察】推出的一个全新的板块,感兴趣的小伙伴可以直接搜索公众号名字关注哦!面试现场系列旨在回放真实的面试过程,并对面试题进行全面解析,提供多种思路,比较优劣,希望对大家的面试有所帮助。



640?往期回顾:

【面试现场】如何判断一个数是否在40亿个整数中?

【面试现场】如何实现可以获取最小值的栈?

【面试现场】为什么要分稳定排序和非稳定排序?

【面试现场】如何编程解决华容道问题?

【面试现场】如何找到字符串中的最长回文子串?

【面试现场】如何在500w个单词中统计特定前缀的单词有多少个?

【面试现场】如何在10亿数中找出前1000大的数

-END-

    喜欢本文的朋友们,欢迎关注订阅号Java学习之道,收看更多精彩内容!

640?

    一 起640?力吧!

640?wx_fmt=png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表中的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库中的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值