zoukankan      html  css  js  c++  java
  • 943.Find the Shortest Superstring --- 旅行商问题&状态压缩DP

    943.Find the Shortest Superstring

    Given an array A of strings, find any smallest string that contains each string in A as a substring.

    We may assume that no string in A is substring of another string in A.

    Example 1:

    Input: ["alex","loves","leetcode"]

    Output: "alexlovesleetcode"

    Explanation: All permutations of "alex","loves","leetcode" would also be accepted.

    2019.1.19算法群里的题目:这道题涉及到旅行商问题,解法是状态压缩dp

    参考大神的解法,梳理了下解法;

    题意

    给一个字符串序列,找到包含序列中所有字符串的最小的字符串

    分析

    • (1)先建图:预处理计算出Cost,也就是一个节点到另一个节点的权重,这里的话,,g[i][j]表示将A[j]加到A[i]的后面,路径的长度:

    • (2) 题目转化为找一条访问过每个节点一次的最短的路径

    • (3) 记忆化DP:

      • dp[s][i] :表示访问了节点集合s,且最后一个节点是i的最短的路径,注意这里s是一个Binary String,表示哪些节点已经访问过了,为1的节点是已经访问过的;

      Assume we want to travel nodes: {n1, n2, n3, n4} then
      i = 2 ^ n1 +2 ^ n2 +2 ^ n3 +2 ^ n4;

      • path[s][i]:表示访问了节点集合s,并且最后一个节点是i,i前面的一个节点; 记录路径中,i的前面的一个点,以便于重建途径的时候的回溯
    • (4) dp更新策略:
      dp[s][i] = min(dp[s - 2^i][j] + g[j][i]) #将j加到i的后面

    代码

    /**
    题意:给一个字符串序列,找到包含序列中所有字符串的最小的子串
    分析:
    */
    
    class Solution {
        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++) {
                    graph[i][j] = calCost(A, i, j);  //把j加到i后面的路径长度,即图中i->j的边长
                    graph[j][i] = calCost(A, j, i);
                }
            }
            
            int[][] dp = new int[1 << n][n];  //dp[s][i] :表示访问了节点集合s,且最后一个节点是i的最短的路径
            int[][] path = new int[1 << n][n];
            int min = Integer.MAX_VALUE, last = -1;
            
            for (int state = 1; state < (1 << n); state++) {  //枚举所有的节点集合组成状态
                Arrays.fill(dp[state], Integer.MAX_VALUE);
                for (int node = 0; node < n; node++) {
                    if ((state & (1 << node)) > 0) { //判断node在不在节点集合中
                        int leftState = state - (1 << node);  //剩下的节点集合
                        if (leftState == 0) {  //如果只剩一个节点了,则当前长度就是node的长度
                            dp[state][node] = A[node].length();
                        } else {
                            for (int k = 0; k < n; k++) {  //dp更新
                                if (dp[leftState][k] != Integer.MAX_VALUE && 
                                    dp[leftState][k] + graph[k][node] < dp[state][node]) {  //如果访问过了leftState且经过k点的路径更小,则更
                                    dp[state][node] = dp[leftState][k] + graph[k][node];
                                    path[state][node] = k;
                                }
                            }
                        }
                    }
                    if (state == (1 << n) - 1 && dp[state][node] < min) {
                        min = dp[state][node];
                        last = node;
                    }
                    //System.out.println(dp[state][node]);
                }
            }
            //建立路径        
            StringBuilder sb = new StringBuilder();
            int cur = (1 << n) - 1;
            Stack<Integer> stack = new Stack<>();
            while (cur > 0) {
                stack.push(last);
                int temp = cur;
                cur -= (1 << last);
                last = path[temp][last];
            }
    		        
            int i = stack.pop();
            sb.append(A[i]);
            while (!stack.isEmpty()) {
                int j = stack.pop();
                sb.append(A[j].substring(A[j].length() - graph[i][j]));
                i = j;
            }
            return sb.toString();
        }
        
        private int calCost(String[] A, int i, int j) {
            for (int pos = 1; pos < A[i].length(); pos++) {
                if (A[j].startsWith(A[i].substring(pos))) {
                    return A[j].length() - A[i].length() + pos;
                }
            }
            return A[j].length();
        }
    }
    
    
  • 相关阅读:
    序列化注意事项
    HTML5的新结构标签
    MVC模型
    CSS选择器权重计算规则
    HTML常用布局
    盒模型
    Spring Security 学习笔记-session并发控制
    java实例之随机点名
    java之方法重载
    java之方法
  • 原文地址:https://www.cnblogs.com/shawshawwan/p/10291893.html
Copyright © 2011-2022 走看看