zoukankan      html  css  js  c++  java
  • 动态规划-TSP问题-最短超级串

    2020-03-03 22:55:08

    问题描述:

    给定一个字符串数组 A,找到以 A 中每个字符串作为子字符串的最短字符串。

    我们可以假设 A 中没有字符串是 A 中另一个字符串的子字符串。

    示例 1:

    输入:["alex","loves","leetcode"]
    输出:"alexlovesleetcode"
    解释:"alex","loves","leetcode" 的所有排列都会被接受。

    示例 2:

    输入:["catg","ctaagt","gcta","ttca","atgcatc"]
    输出:"gctaagttcatgcatc"

    提示:

    1 <= A.length <= 12
    1 <= A[i].length <= 20

    问题求解:

    解法一:暴力求解

    首先我们要明确的就是,本题可以转化成图论的题目,就是在一个图中要遍历所有的节点一次,最后路径的最小值是多少。(这里和TSP略有不同,即我们不需要返回起始节点)

    暴力求解,可以理解为全排列,只不过我们做了一些剪枝操作进行了加速。

    时间复杂度:O(n!)

        int res = (int)1e9;
        List<Integer> path;
        int n;
        
        public String shortestSuperstring(String[] A) {
            n = A.length;
            int[][] graph = new int[n][n];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    for (int k = Math.min(A[i].length(), A[j].length()); k >= 0; k--) {
                        if (A[j].substring(0, k).equals(A[i].substring(A[i].length() - k))) {
                            graph[i][j] = A[j].length() - k;
                            break;
                        }
                    }
                }
            }
            helper(A, graph, 0, 0, 0, new ArrayList<>());
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < n; i++) {
                int node = path.get(i);
                String s = A[node];           
                if (i == 0) sb.append(s);
                else sb.append(s.substring(s.length() - graph[path.get(i - 1)][node]));
            }
            return sb.toString();
        }
        
        private void helper(String[] A, int[][] graph, int k, int used, int curr, List<Integer> curr_p) {
            if (curr >= res) return;
            if (k == n) {
                res = curr;
                path = new ArrayList<>(curr_p);
                return;
            }
            for (int i = 0; i < n; i++) {
                if ((used & (1 << i)) != 0) continue;
                curr_p.add(i);
                helper(A, graph, k + 1, used | (1 << i), k == 0 ? A[i].length() : curr + graph[curr_p.get(curr_p.size() - 2)][i], curr_p);
                curr_p.remove(curr_p.size() - 1);
            }
        }
    

      

    解法二:DP

    dp[s][i] : 当前访问过的节点状态为s,且以i为结尾的最短路径。

    init :

    dp[1 << i][i] = A[i].length()

    transition :

    对于dp[s][i]我们需要去枚举所有的parent节点,计算得到当前的最小值。

    dp[s][i] = min{dp[s - (1 << i)][j] + graph[j][i]) 将A[i]追加到A[j]后面。

    时间复杂度:O(2 ^n * n ^ 2)    同TSP问题

        public String shortestSuperstring(String[] A) {
            int n = A.length;
            int[][] graph = new int[n][n];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    for (int k = Math.min(A[i].length(), A[j].length()); k >= 0; k--) {
                        if (A[j].substring(0, k).equals(A[i].substring(A[i].length() - k))) {
                            graph[i][j] = A[j].length() - k;
                            break;
                        }
                    }
                }
            }
            int[][] dp = new int[1 << n][n];
            int[][] parent = new int[1 << n][n];
            for (int i = 0; i < 1 << n; i++) {
                Arrays.fill(dp[i], (int)1e9);
                Arrays.fill(parent[i], -1);
            }
            for (int i = 0; i < n; i++) dp[1 << i][i] = A[i].length();
            for (int s = 1; s < 1 << n; s++) {
                for (int i = 0; i < n; i++) {
                    if ((s & (1 << i)) == 0) continue;
                    int prev = s - (1 << i);
                    for (int j = 0; j < n; j++) {
                        if (dp[prev][j] + graph[j][i] < dp[s][i]) {
                            dp[s][i] = dp[prev][j] + graph[j][i];
                            parent[s][i] = j;
                        }
                    }
                }
            }
            int curr = -1;
            int min = (int)1e9;
            for (int i = 0; i < n; i++) {
                if (dp[(1 << n) - 1][i] < min) {
                    min = dp[(1 << n) - 1][i];
                    curr = i;
                }
            }
            
            int s = (1 << n) - 1;
            String res = "";
            while (s > 0) {
                int prev = parent[s][curr];
                if (prev == -1) res = A[curr] + res;
                else res = A[curr].substring(A[curr].length() - graph[prev][curr]) + res;
                s &= ~(1 << curr);
                curr = prev;
            }
            
            return res;
        }
    

      

  • 相关阅读:
    Streams那些事之概述与原理
    ORA12514: ORACLE 监听错误
    使用软件工具插件 备忘
    jquery 弹出遮罩插件 prettyPhoto 参数说明
    SQL 9位随机码
    向上下左右不间断无缝滚动的效果(兼容火狐和IE)[转]
    SQL 将一串字符串转换为列插入临时表
    jQuery插件开发全解析[转]
    DIV+CSS命名规范
    ASP.NET中Session跨站点共享实现方式
  • 原文地址:https://www.cnblogs.com/hyserendipity/p/12405424.html
Copyright © 2011-2022 走看看