Simulation of "Algorithm Series"

Introduction

  Most of the simulation questions give people the feeling that the brain can understand, but the hands just can't adjust it, and the ability to master the code is very high . But there is a trap here. For most questions, the simulation method is not a good choice . Can you simulate the questions you want to dynamically plan? For the simulation of the moving rules, some of the questions can’t be calculated by the computer until the universe restarts. Maybe simulation is the easiest way to think about difficulty, but it is not necessarily the best choice for the current question. If there are other solutions, don’t choose The dumbest way to simulate. But there are also questions that come directly from the simulation method, and there is no better solution, and some are still common exam questions (such as: spiral matrix), why? Because it is a test of code mastery.

theoretical basis

  In fact, the theoretical basis of simulation should be more abstract ability . The questions on leetcode all have a characteristic, partial algorithm implementation, and the basic algorithm model can be seen at the first time on the question surface. But one day when you were interviewing, you found that the usual algorithm questions with dozens of words turned into small essays with hundreds of words. The interview requirement is that you are required to abstract the algorithm model and then use a suitable algorithm to solve it. At this time, the abstraction ability is poor, and the questions cannot be read clearly, let alone solve the problems. The abstraction in the simulation questions is considered more in leetcode, such as the spiral matrix, life matrix and so on. There are no tricks in the simulation questions, more practice is the tricks. It is best to be able to know at the first time that this is a simulation question, instead of trying to show off the code, because usually you can't figure it out, and you are wasting precious time in vain!

Problem solving experience

  • Simulation questions are generally simple in terms of thinking difficulty and difficult in code implementation.
  • For an algorithm problem, if you can use other solutions, don't use the simulation method, because the time complexity is relatively high.
  • The simulation questions are very good at testing the ability to master the code.
  • If you want to do well in mock questions, abstract ability is indispensable.
  • There is an advantage of doing more mock questions, that is, we can know whether the question is a mock question at the first time, without having to think about clever solutions, otherwise we will waste time in unreasonable ways.

algorithm topic

43. String multiplication

insert image description here
Topic Analysis: Using arrays to imitate multiplication, the detailed analysis is as follows.

num1的第i位(高位从0开始)和num2的第j位相乘的结果在乘积中的位置是[i+j, i+j+1]
例: 123 * 45,  123的第1位 2 和45的第0位 4 乘积 08 存放在结果的第[1, 2]位中

 index:    0 1 2 3 4  
 
           1 2 3
       *     4 5
       ---------
             1 5
           1 0
         0 5
       ---------
         0 6 1 5
           1 2
         0 8
       0 4
       ---------
       0 5 5 3 5
这样我们就可以单独都对每一位进行相乘计算把结果存入相应的index中   

code show as below:

/**
 * 模拟
 *
 **/
class Solution {
    public String multiply(String num1, String num2) {
        int n1 = num1.length() - 1;
        int n2 = num2.length() - 1;
        if(n1 < 0 || n2 < 0) return "";
        int[] mul = new int[n1 + n2 + 2];
        
        for(int i = n1; i >= 0; --i) {
            for(int j = n2; j >= 0; --j) {
                int bitmul = (num1.charAt(i) - '0') * (num2.charAt(j) - '0');      
                bitmul += mul[i + j + 1]; // 先加低位判断是否有新的进位
                
                mul[i + j] += bitmul / 10;
                mul[i + j + 1] = bitmul % 10;
            }
        }
        
        StringBuilder sb = new StringBuilder();
        int i = 0;
        // 去掉前导0
        while(i < mul.length-1 && mul[i] == 0) 
            i++;
        for(; i < mul.length; ++i)
            sb.append(mul[i]);
        return sb.toString();
    }
}

54. Spiral Matrix

insert image description here
Topic analysis: This is a classic simulation question, there is no special solution, the test is the ability to master the code, understand the meaning of the question, and then simulate the entire traversal process.
code show as below:

/**
 * 模拟
 */
class Solution {
    public List<Integer> spiralOrder(int[][] matrix) {

        List<Integer> res = new ArrayList<>();
        if (matrix.length == 0) {
            return res;
        }

        int start_x = 0;
        int start_y = 0;
        int direction = 0;
        int top_border = -1; // 上边界
        int right_border = matrix[0].length; // 右边界
        int bottom_border = matrix.length; // 下边界
        int left_border = -1; // 左边界

        // direction 向右:0,向下:1,向左2,向上:3
        while (true) {

            // 遍历完后返回
            if (res.size() == matrix.length * matrix[0].length) {
                return res;
            }
            // 注意,二维数组的行列,和坐标x,y轴,对应关系为 行 = y,列 = x
            res.add(matrix[start_y][start_x]);
            switch (direction) {
                // 向右
                case 0:
                    if (start_x + 1 == right_border) {
                        // 到底则改变方向,向下,向下移一行,上边界也向下移一行
                        direction = 1;
                        start_y += 1;
                        top_border += 1;
                    } else {
                        // 如果没到右边界,则持续往右
                        start_x += 1;
                    }
                    break;
                // 向下
                case 1:
                    if (start_y + 1 == bottom_border) {
                        // 到底则改变方向,向左,向左移一列,右边界也向左移一列
                        direction = 2;
                        start_x -= 1;
                        right_border -= 1;
                    } else {
                        // 如果没到下边界,则持续往下
                        start_y += 1;
                    }
                    break;
                // 向左
                case 2:
                    if (start_x - 1 == left_border) {
                        // 到底则改变方向,向上,向上移一行,下边界也向上移一行
                        direction = 3;
                        start_y -= 1;
                        bottom_border -= 1;
                    } else {
                        // 如果没到左边界,则持续往左
                        start_x -= 1;
                    }
                    break;
                // 向上
                case 3:
                    if (start_y - 1 == top_border) {
                        // 到底则改变方向,向右,向右移一列,左边界也向右移一列
                        direction = 0;
                        start_x += 1;
                        left_border += 1;

                    } else {
                        // 如果没到上边界,则持续往上
                        start_y -= 1;
                    }
                    break;
            }
        }
    }
}

59. Spiral Matrix II

insert image description here
Topic analysis: Same as the previous question, the interview questions are often tested, and the test is the ability to master the code and rotate the entire array.
code show as below:

/**
 * 模拟
 */
class Solution {
    public int[][] generateMatrix(int n) {

        int[][] res = new int[n][n];

        // 为零直接返回
        if (n == 0) {
            return res;
        }

        int start_row = 0; // 行位置
        int start_column = 0; // 列位置
        int direction = 0; // 方向,向右:0,向下:1,向左2,向上:3
        int top_border = -1; // 上边界
        int bottom_border = n; // 下边界
        int left_border = -1; // 左边界
        int right_border = n; // 右边界

        for (int i = 1; i <= n * n; i++) {

            res[start_row][start_column] = i;
            switch (direction) {
                // 向右
                case 0:
                    // 判断是否到右边界
                    if (start_column + 1 == right_border) {
                        // 到底则改变方向,向下
                        direction = 1;
                        // 位置向下移一行,上边界也向下移一行
                        start_row += 1;
                        top_border += 1;
                    } else {
                        // 如果没到右边界,则持续往右
                        start_column += 1;
                    }
                    break;
                // 向下
                case 1:
                    // 判断是否到下边界
                    if (start_row + 1 == bottom_border) {
                        // 到底则改变方向,向左
                        direction = 2;
                        // 位置向左移一列,右边界也向左移一列
                        start_column -= 1;
                        right_border -= 1;
                    } else {
                        // 如果没到下边界,则持续往下
                        start_row += 1;
                    }
                    break;
                // 向左
                case 2:
                    // 判断是否到左边界
                    if (start_column - 1 == left_border) {
                        // 到底则改变方向,向上
                        direction = 3;
                        // 位置向上移一行,下边界也向上移一行
                        start_row -= 1;
                        bottom_border -= 1;
                    } else {
                        // 如果没到左边界,则持续往左
                        start_column -= 1;
                    }
                    break;
                // 向上
                case 3:
                    // 判断是否到上边界
                    if (start_row - 1 == top_border) {
                        // 到底则改变方向,向右
                        direction = 0;
                        // 位置向右移一列,左边界也向右移一列
                        start_column += 1;
                        left_border += 1;

                    } else {
                        // 如果没到上边界,则持续往上
                        start_row -= 1;
                    }
                    break;
            }
        }
        return res;
    }
}

68. Align text left and right

insert image description here
Topic analysis: For difficult simulation questions, according to the greedy algorithm described in the question stem, for each line, we first determine how many words can be placed at most, so that we can get the number of spaces in the line, so as to determine the number of spaces between words in the line number.
code show as below:

/**
 * 模拟
 */
class Solution {
    public List<String> fullJustify(String[] words, int maxWidth) {
        List<String> ans = new ArrayList<String>();
        int right = 0, n = words.length;
        while (true) {
            int left = right; // 当前行的第一个单词在 words 的位置
            int sumLen = 0; // 统计这一行单词长度之和
            // 循环确定当前行可以放多少单词,注意单词之间应至少有一个空格
            while (right < n && sumLen + words[right].length() + right - left <= maxWidth) {
                sumLen += words[right++].length();
            }

            // 当前行是最后一行:单词左对齐,且单词之间应只有一个空格,在行末填充剩余空格
            if (right == n) {
                StringBuffer sb = join(words, left, n, " ");
                sb.append(blank(maxWidth - sb.length()));
                ans.add(sb.toString());
                return ans;
            }

            int numWords = right - left;
            int numSpaces = maxWidth - sumLen;

            // 当前行只有一个单词:该单词左对齐,在行末填充剩余空格
            if (numWords == 1) {
                StringBuffer sb = new StringBuffer(words[left]);
                sb.append(blank(numSpaces));
                ans.add(sb.toString());
                continue;
            }

            // 当前行不只一个单词
            int avgSpaces = numSpaces / (numWords - 1);
            int extraSpaces = numSpaces % (numWords - 1);
            StringBuffer sb = new StringBuffer();
            sb.append(join(words, left, left + extraSpaces + 1, blank(avgSpaces + 1))); // 拼接额外加一个空格的单词
            sb.append(blank(avgSpaces));
            sb.append(join(words, left + extraSpaces + 1, right, blank(avgSpaces))); // 拼接其余单词
            ans.add(sb.toString());
        }
    }

    // blank 返回长度为 n 的由空格组成的字符串
    public String blank(int n) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < n; ++i) {
            sb.append(' ');
        }
        return sb.toString();
    }

    // join 返回用 sep 拼接 [left, right) 范围内的 words 组成的字符串
    public StringBuffer join(String[] words, int left, int right, String sep) {
        StringBuffer sb = new StringBuffer(words[left]);
        for (int i = left + 1; i < right; ++i) {
            sb.append(sep);
            sb.append(words[i]);
        }
        return sb;
    }
}

289. The Game of Life

insert image description here
insert image description here
Topic analysis: If in-place algorithm is needed, use an array to record more information. In addition to 0 and 1, the int type can store more information. -1 means that the cell used to be alive and now it is dead, and 2 means that the cell used to be The dead are now alive.
code show as below:

/**
 * 模拟 
 * 
 */
class Solution {
    public void gameOfLife(int[][] board) {
        int[] neighbors = {0, 1, -1};

        int rows = board.length;
        int cols = board[0].length;

        // 遍历面板每一个格子里的细胞
        for (int row = 0; row < rows; row++) {
            for (int col = 0; col < cols; col++) {

                // 对于每一个细胞统计其八个相邻位置里的活细胞数量
                int liveNeighbors = 0;

                for (int i = 0; i < 3; i++) {
                    for (int j = 0; j < 3; j++) {

                        if (!(neighbors[i] == 0 && neighbors[j] == 0)) {
                            // 相邻位置的坐标
                            int r = (row + neighbors[i]);
                            int c = (col + neighbors[j]);

                            // 查看相邻的细胞是否是活细胞
                            if ((r < rows && r >= 0) && (c < cols && c >= 0) && (Math.abs(board[r][c]) == 1)) {
                                liveNeighbors += 1;
                            }
                        }
                    }
                }

                // 规则 1 或规则 3 
                if ((board[row][col] == 1) && (liveNeighbors < 2 || liveNeighbors > 3)) {
                    // -1 代表这个细胞过去是活的现在死了
                    board[row][col] = -1;
                }
                // 规则 4
                if (board[row][col] == 0 && liveNeighbors == 3) {
                    // 2 代表这个细胞过去是死的现在活了
                    board[row][col] = 2;
                }
            }
        }

        // 遍历 board 得到一次更新后的状态
        for (int row = 0; row < rows; row++) {
            for (int col = 0; col < cols; col++) {
                if (board[row][col] > 0) {
                    board[row][col] = 1;
                } else {
                    board[row][col] = 0;
                }
            }
        }
    }
}

back to the homepage

Some feelings about brushing Leetcode 500+ questions

Next

Bit Operations in Algorithm Series

Guess you like

Origin blog.csdn.net/qq_22136439/article/details/126322828