字符串最少由多少回文子串构成

昨天的腾讯笔试题

第五题,题意大概是这样的

  1. 第一行输入一个字符串 s,1 <= s.length() <= 400
  2. 第二行输入该组有多少个测试 n
  3. 后面n行,每行输入两个数字,l,r用空格分割,l和r分别表示s的子串左右边界,1 <= l <= r <= s.length()
    例子:
输入
ababa
4
1 5
2 5
1 4
2 4

输出
1
2
2
1

解释:1 5表示子串为ababa,此时本就为回文,所以最少由一个回文串构成,2 5表示子串为baba,此时可由bab+a构成,也可由b+aba构成,所以输出为2

题解

由于昨天在这道题上浪费了快50min,且未得分,心有不甘,感觉前半部分思路正确,但是后面计算最少组成的时候就脑袋宕机了,故在LeetCode上找了一个类似的题,进行解答,最后通过,便写下该博客。题为:分割回文串 II,给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串,返回符合要求的最少分割次数。所以此题与笔试题是差不多的,在笔试题的返回答案上减1即为该lc题的答案

程序

思路为

  1. 建立一个boolean[s.length()][s.length()]的dp矩阵
  2. i表示子串开始位置,j表示子串结束位置,利用矩阵上三角进行处理该子串是否为回文串
  3. 建立一个同等大小的int矩阵res,也是利用上三角存放该子串最少可由多少个回文串组成
import java.util.Arrays;

public class CycleString {
     
    public static void main(String[] args) {
     
        String s = "ababaccc";
        int len = s.length();
        boolean[][] dp = new boolean[len][len];
        for(int i = len - 1;i >= 0;i--){
     
            dp[i][i] = true;
            for (int j = i+1; j < len ; j++) {
     
                if(s.charAt(i) == s.charAt(j)){
     
                    dp[i][j] = i == j - 1 || dp[i+1][j-1];
                }
            }
        }
        for (boolean[] booleans : dp) {
     
            System.out.println(Arrays.toString(booleans));
        }
        int[][] res = new int[len][len];
        for (int i = len - 1; i >= 0 ; i--) {
     
            for (int j = i; j < len; j++) {
     
                res[i][j] = len;
                if(dp[i][j]){
     
                    res[i][j] = 1;
                }else{
     
                    for (int k = i+1; k <=j ; k++) {
     
                        res[i][j] = Math.min(res[i][j],res[i][k-1]+res[k][j]);
                    }
                }
            }
        }
        for (int[] re : res) {
     
            System.out.println(Arrays.toString(re));
        }
    }
}

上述代码中打印结果如下

[true, false, true, false, true, false, false, false]
[false, true, false, true, false, false, false, false]
[false, false, true, false, true, false, false, false]
[false, false, false, true, false, false, false, false]
[false, false, false, false, true, false, false, false]
[false, false, false, false, false, true, true, true]
[false, false, false, false, false, false, true, true]
[false, false, false, false, false, false, false, true]
[1, 2, 1, 2, 1, 2, 2, 2]
[0, 1, 2, 1, 2, 3, 3, 3]
[0, 0, 1, 2, 1, 2, 2, 2]
[0, 0, 0, 1, 2, 3, 3, 3]
[0, 0, 0, 0, 1, 2, 2, 2]
[0, 0, 0, 0, 0, 1, 1, 1]
[0, 0, 0, 0, 0, 0, 1, 1]
[0, 0, 0, 0, 0, 0, 0, 1]

经过人工验证,没毛病,遂放到lc上修改一下进行了提交
字符串最少由多少回文子串构成_第1张图片

emmm,一顿操作猛如虎,查询通过双百五,至少过了,而且这个用在笔试题上,应该会有效点吧,毕竟是在一个字符串上返回其多个子串最少由多少个回文串构成。复杂度确实高,但是胜在简单易懂,慢慢来吧。

笔试题对应解

import java.util.Scanner;

public class CycleString {
     
    public static void main(String[] args) {
     
        Scanner in = new Scanner(System.in);
        String s = in.nextLine();
        int n = in.nextInt();
        int[][] input = new int[n][2];
        for (int i = 0; i < n; i++) {
     
            for (int j = 0; j < 2; j++) {
     
                input[i][j] = in.nextInt() - 1;
            }
        }
        in.close();
        int len = s.length();
        boolean[][] dp = new boolean[len][len];
        for(int i = len - 1;i >= 0;i--){
     
            dp[i][i] = true;
            for (int j = i+1; j < len ; j++) {
     
                if(s.charAt(i) == s.charAt(j)){
     
                    dp[i][j] = i == j - 1 || dp[i+1][j-1];
                }
            }
        }
        int[][] res = new int[len][len];
        for (int i = len - 1; i >= 0 ; i--) {
     
            for (int j = i; j < len; j++) {
     
                res[i][j] = len;
                if(dp[i][j]){
     
                    res[i][j] = 1;
                }else{
     
                    for (int k = i+1; k <=j ; k++) {
     
                        res[i][j] = Math.min(res[i][j],res[i][k-1]+res[k][j]);
                    }
                }
            }
        }
        for (int[] ints : input) {
     
            System.out.println(res[ints[0]][ints[1]]);
        }
    }
}

哎,笔试的时候就是这个思路,但是求res的时候,为了追求小的时间复杂度,陷入怪圈,没有使用代码中的for k,导致没拿分,做题还是要保持冷静。

你可能感兴趣的:(Java,腾讯,java,字符串)