数据结构与算法学习笔记(训练营四)-经典面试18(ppt-5)

  • 对于一个字符串, 从前开始读和从后开始读是一样的, 我们就称这个字符串是回文串。例如"ABCBA","AA", "A" 是回文串, 而"ABCD", "AAB"不是回文串。牛牛特别喜欢回文串, 他手中有一个字符串s, 牛牛在思考能否从字 符串中移除部分(0个或多个)字符使其变为回文串,并且牛牛认为空串不是回文串。牛牛发现移除的方案可能有 很多种, 希望你来帮他计算一下一共有多少种移除方案可以使s变为回文串。对于两种移除方案, 如果移除的字 符依次构成的序列不一样就是不同的方案。
    例如,XXY 4种 ABA 5种
    【说明】 这是今年的原题,提供的说明和例子都很让人费解。现在根据当时题目的所有测试用例,重新解释当时的题目 含义: 1)"1AB23CD21",你可以选择删除A、B、C、D,然后剩下子序列{1,2,3,2,1},只要剩下的子序列是同一个,那 么就只算1种方法,和A、B、C、D选择什么样的删除顺序没有关系。 2)"121A1",其中有两个{1,2,1}的子序列,第一个{1,2,1}是由{位置0,位置1,位置2}构成,第二个{1,2,1} 是由{位置0,位置1,位置4}构成。这两个子序列被认为是不同的子序列。也就是说在本题中,认为字面值一样 但是位置不同的字符就是不同的。 3)其实这道题是想求,str中有多少个不同的子序列,每一种子序列只对应一种删除方法,那就是把多余的东 西去掉,而和去掉的顺序无关。
    4)也许你觉得我的解释很荒谬,但真的是这样,不然解释不了为什么,XXY 4种 ABA 5种,而且其他的测 试用例都印证了这一点。
public class PalindromeNum {

    // 范围上的尝试模型
    public static int palindromeNum(String str){
        if(str == null || str.equals("")){
            return 0;
        }

        char[] c = str.toCharArray();
        int n = c.length;
        int[][] dp = new int[n][n];
        // 对角线全是1
        for (int i = 0; i < c.length; i++) {
            dp[i][i] = 1;
        }

        // 倒数第二条对角线
        for (int i = 0; i < n-1; i++) {
            dp[i][i+1] = c[i] == c[i+1] ? 3 : 2;
        }

        // 普遍位置,倒数前二行都已经填过了,不用填,
        for (int i = n - 3; i >= 0 ; i--) {
            for (int j = i+2; j < n; j++) {
                dp[i][j] = dp[i+1][j] + dp[i][j-1] - dp[i+1][j-1];
                if(c[i] == c[j]){
                    dp[i][j] += dp[i+1][j-1] + 1;
                }
            }
        }

        return dp[0][n-1];
    }


    public static void main(String[] args) {
        String str1 = "xxy";
        String str2 = "ABA";
        System.out.println(palindromeNum(str1));
        System.out.println(palindromeNum(str2));
    }
}
  • 给定一个字符串str,求最长回文子序列长度。
/**
 * 给定一个字符串str,求最长回文子序列长度。
 */
public class MaxLenPalindromeSubSeq {

    public static int maxLenPalindromeSubSeq(String str){
        if(str == null || str.equals("")){
            return  0;
        }
        // 范围上尝试的模型
        // dp[i][j] 表示以开头,j结尾的子串中最长回文子序列是多少
        // 由于是范围上的尝试模型,则左下部分无效
        int n = str.length();
        char[] c = str.toCharArray();
         int[][] dp = new int[n][n];
        // 对角线
        for (int i = 0; i < n; i++) {
            dp[i][i] = 1;
        }

        // 倒数第二条对角线
        for (int i = 0; i < n-1; i++) {
            dp[i][i+1] = c[i] == c[i+1] ? 2 : 1;
        }

        // 普遍位置
        // 1.i...j的回文子串以不以i,j结尾dp[i][j] = dp[i+1][j-1]
        // 2.i...j的回文子串以i开头,不以j结尾 dp[i][j] = dp[i][j-1]
        // 3.i...j的回文子串不以i开头,以j结尾 dp[i][j] = dp[i+1][j]
        // 4.i...j的回文子串以i开头,以j结尾 dp[i][j] = dp[i+1][j-1](i,j位置字符相等)

        // 从下往上,从左往右
        // 倒数第三行开始
        for (int i = c.length-3; i >= 0; i--) {
            for (int j = i+2; j < n; j++) {
                dp[i][j] = Math.max(dp[i+1][j-1],Math.max(dp[i][j-1],dp[i+1][j]));
                if(c[i] == c[j]){
                    dp[i][j] = Math.max(dp[i][j],dp[i+1][j-1]+2);
                }
            }
        }
        return dp[0][n-1];
    }
    
}

  • 给定一个二维数组matrix,每个单元都是一个整数,有正有负。最开始的时候小Q操纵 一条长度为0的蛇蛇从矩阵最左侧任选一个单元格进入地图,蛇每次只能够到达当前位 置的右上相邻,右侧相邻和右下相邻的单元格。蛇蛇到达一个单元格后,自身的长度会 瞬间加上该单元格的数值,任何情况下长度为负则游戏结束。小Q是个天才,他拥有一 个超能力,可以在游戏开始的时候把地图中的某一个节点的值变为其相反数(注:最多 只能改变一个节点)。问在小Q游戏过程中,他的蛇蛇最长长度可以到多少?
    比如:
    1 -4 10
    3 -2 -1
    2 -1 0
    0 5 -2
    最优路径为从最左侧的3开始,3 -> -4(利用能力变成4) -> 10。所以返回17。
  • 给定一个字符串str,str表示一个公式,公式里可能有整数、加减乘除符号和左右 括号,返回公式的计算结果。
    【举例】
    str="48((70-65)-43)+81",返回-1816。
    str="3+14",返回7。
    str="3+(1
    4)",返回7。
    【说明】 1.可以认为给定的字符串一定是正确的公式,即不需要对str做公式有效性检查。 2.如果是负数,就需要用括号括起来,比如"4(-3)"。但如果负数作为公式的开头 或括号部分的开头,则可以没有括号,比如"-34"和"(-3*4)"都是合法的。 3.不用考虑计算过程中会发生溢出的情况。
/**
 * 给定一个字符串str,str表示一个公式,公式里可能有整数、加减乘除符号和左右 括号,返回公式的计算结果。
 * 【举例】
 * str="48*((70-65)-43)+8*1",返回-1816。
 * str="3+1*4",返回7。
 * str="3+(1*4)",返回7。
 * 【说明】 1.可以认为给定的字符串一定是正确的公式,即不需要对str做公式有效性检查。 2.如果是负数,
 * 就需要用括号括起来,比如"4*(-3)"。但如果负数作为公式的开头 或括号部分的开头,则可以没有括号,比
 * 如"-3*4"和"(-3*4)"都是合法的。 3.不用考虑计算过程中会发生溢出的情况。
 */
public class Calculate {
    public static int calculate(String str){
        char[] c = str.toCharArray();
        return process(c,0)[0];
    }

    // 从index开始算,返回index开始计算的有效结果,和计算到的位置
    //0位置,结果;1位置,此次计算到的位置
    public static int[] process(char[] c,int index){
        // 当前的数字
        int cur = 0;
        LinkedList<String> stack = new LinkedList<>();
        int[] res = new int[2];
        // 越界或者遇到右括号停止
        while (index < c.length && c[index] != ')'){
            // 如果遇到的是数字就收集数字
            if(c[index] >= '0' && c[index] <= '9'){
                // 数字
                cur = cur * 10 + (c[index] - '0');
                index ++;
            }else if(c[index] == '+' || c[index] == '-' || c[index] == '*' || c[index] == '/'){
                // 如果栈顶是乘除先计算在放
                if("*".equals(stack.peekFirst()) || "/".equals(stack.peekFirst())){
                    String op = stack.pop();
                    String num = stack.pop();
                    int re = 0;
                    if("*".equals(op)){
                        re = cur*Integer.parseInt(num);

                    }else {
                        re = cur/Integer.parseInt(num);
                    }
                    stack.push(re+"");
                    stack.push(String.valueOf(c[index]));
                    cur = 0;
                }else{
                    stack.push(cur+"");
                    stack.push(String.valueOf(c[index]));
                    cur = 0;
                }
                index++;
            }else{
                //左括号调用递归过程
                int[] process = process(c, index + 1);
                if("*".equals(stack.peekFirst()) ||"/".equals(stack.peekFirst())){
                    String op = stack.pop();
                    String num = stack.pop();
                    int re = 0;
                    if("*".equals(op)){
                        re = process[0]*Integer.parseInt(num);

                    }else {
                        re = process[0]/Integer.parseInt(num);
                    }
                    cur = re;
                    index = process[1]+1;
                }else{
                    cur = process[0];
                    index = process[1]+1;
                }
            }
        }

        int d = 0;
        if("*".equals(stack.peekFirst()) || "/".equals(stack.peekFirst())){
            String op = stack.pop();
            String num = stack.pop();
            int re = 0;
            if("*".equals(op)){
                re = cur*Integer.parseInt(num);

            }else {
                re = cur/Integer.parseInt(num);
            }
            stack.push(re+"");
        }else{
            stack.push(cur+"");
        }

        while (stack.size() >=2){
            int one = Integer.valueOf(stack.pollLast());
            String op = stack.pollLast();
            int two = Integer.valueOf(stack.pollLast());
            if(op.equals("+")){
                d = one + two;
            }else{
                d = one - two;
            }
            stack.addLast(d+"");
        }

        return new int[]{d,index};
    }


    public static void main(String[] args) {
       String str = "48*((70-65)-43)+8*1";
        System.out.println(calculate(str));
    }
}

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容