目录

  • 题目描述
  • 暴力搜索分析
  • 暴力搜索优化
  • 动态规划
  • 参考链接

题目描述

输入:字符串数组String[] A
输出:一个字符串result,A中每一个字符串是result的子串,并且reuslt是符合这个条件的最短的字符串。
举例:
输入: [“alex”,“loves”,“leetcode”]
输出: “alexlovesleetcode”

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

暴力搜索分析

分析:result中包含所有A中的字符串,那把A中字符串一次拼接起来肯定满足这个条件。A= [“catg”,“ctaagt”,“gcta”],那么"catgctaagtgcta"符合条件。当然这三个字符串的任意一个排列得到的字符串都符合。

分析条件2:要求result是最短的。例如A[0]A[1]拼接在一起,如果A[1]的前缀是A[0]的后缀,那么它们可以共用这部分字符串,result的长度就会降低。"gcta"和"ctaagt"拼接的时候,“cta”就是公共部分,拼接之后可以是“gctaagt”。

根据这些分析我们写一个暴力搜索的版本(套用排列的代码模板)。

class Solution {private String result = null;private String[] A;public String shortestSuperstring(String[] A) {result = null;this.A = A;boolean[] visited = new boolean[A.length];dfs(A.length,visited,new ArrayList<Integer>());return result;}/*** dfs递归调用* @param m*          还需要取几个元素* @param visited*           哪些元素已经被取了,不能再取* @param path*          按顺序访问的元素下标*/private void dfs(int m,boolean[] visited, ArrayList<Integer> path) {if(m == 0){//注意结果需要完全拷贝String str = contanctString(path);if(result == null || result.length() > str.length()){result = str;}return;}for(int i =0;i<A.length;i++){if(visited[i]==false){visited[i] = true;path.add(i);dfs(m-1,visited,path);path.remove(path.size()-1);visited[i] = false;}}}/***把路径中的字符串拼接起来*/private String contanctString(List<Integer> path){String str = A[path.get(0)];for(int i = 1; i< path.size();i++){str = contanctTwoString(str, A[path.get(i)]);}return str;}/***拼接两个字符串*/private String contanctTwoString(String str1 , String str2){int m = Math.min(str1.length(),str2.length());for(int i = m; i>0;i--){if(str1.endsWith(str2.substring(0,i))){return str1+str2.substring(i);}}return str1+str2;}}

时间复杂度O(n!)。
A的长度范围是[1,12]。这个时间复杂度是不能通过的(花花酱视频中的说明)。12!约等于4亿多。可以考虑剪枝策略和缓存策略。

暴力搜索优化

从递归树中我们可以看到相同位置的字符串拼接会有多次操作。例如路径[1,2,3]、[2,3,1]这两个,A[2]和A[3]就要拼接两次。是不是能提前计算出两两字符串拼接后的字符串,可以少一次。
我们要找的是长度最短的字符串,如果能提前把两两字符串拼接后的字符串的长度记录下来,在dfs过程中发现当前长度大于result(上一个最有结果)的长度就可以停止递归。这样我们需要计算一个数组cost[i][j],表示A[j]拼接在A[i]后面需要增加的长度。
例如 A= [“catg”,“ctaagt”,“gcta”], cost[0][0]=0。cost[0][2]=3,因为合并后的字符串catgcta,需要增加cta三个字符串。
代码链接。

动态规划

我们的目标是要将A中每一个字符串添加到result中。在实际操作过程中,每次添加一个字符串,并且前面的字符串怎么添加不影响后续字符串添加。可以使用动态规划。
定义int s 表示访问了哪些节点。例如s=3,表示访问了A[0],A[1]。对于A= [“catg”,“ctaagt”,“gcta”],s最大值等于7。

定义数组dp[s][i] = 经过路径s,到达i状态,并且是以i结尾,并且每个节点只访问一次的最短字符串长度。目标状态是dp[7][i],从dp[7][0]、dp[7][1]、dp[7][2]中选择最小值作为结果。

这里动态方程,不太好表示。可以使用从下向上的方式。
dp[7][0] = min(dp[6][2] + cost[2][0]
, dp[6][1] + cost[1][0]
, dp[5][0] + cost[0][1]
…)
dp[mask ^ (1<<j)][j] = min{dp[mask][i] + cost[i][j]}

初始化,添加每个单个的字符串到结果中。dp[0][0] = A[0].length(),dp[1][1]=A[1].length(),dp[4][2]=A[2].length()

时间复杂度(2^n)。时间复杂度降低很多。这个代码有很多难点。即使会了递归方程,要想实现出来还是有难度的。
难点1,用int 表示数组中每一位是否被选择 。
难点2,动态规划从s=1开始,逐步递增。
难点3,如果题目求最短字符串的长度的话,只要使用一维数组dp[]即可,这里还要请求输出字符串,所以需要记录下走不通路径到达i状态的长度。
难点4,记录路径需要用到parent数组。

class Solution {public String shortestSuperstring(String[] A) {int n = A.length;int[][] cost = new int[n][n];for(int i=0;i<n;i++){for(int j = 0; j<n;j++){cost[i][j] = minLength(A[i], A[j]);}}int[][] dp = new int[1<<n][n];int[][] parent = new int[1<<n][n];for(int s = 0; s < (1<<n); s++){Arrays.fill(dp[s],10000);Arrays.fill(parent[s],-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 j = 0;j<n;j++){//end pointif ((s & (1 << j)) ==0) continue;int pre = s - (1<<j);for(int i =0;i<n;i++){if(dp[pre][i] + cost[i][j] < dp[s][j]){dp[s][j] = dp[pre][i] + cost[i][j];parent[s][j] = i;}}}}int mask = (1<<n)-1;int minCost = dp[mask][0];int endIndex = 0;for(int j =1;j<n;j++){if(dp[mask][j] < minCost){minCost = dp[mask][j] ;endIndex = j;}}String result = "";int cur = endIndex;int s = (1<<n)-1;while(s > 0){int p = parent[s][cur];if(p<0){result = A[cur] + result;break;}else{result = A[cur].substring(A[cur].length()-cost[p][cur]) + result;}s &= ~(1 << cur);cur = p;}return result;}private int minLength(String str1, String str2){int m = Math.min(str1.length(),str2.length());for(int i = m; i>0;i--){if(str1.endsWith(str2.substring(0,i))){return  str2.length()-i;}}return str2.length();}}

参考链接

花花酱,
leetcode

943. Find the Shortest Superstring相关推荐

  1. Genome Assembly as Shortest Superstring

    # 引入正则表达式模块 import redef gen_cf(m, n):"""该函数是用来计算 m序列尾部和 n序列头部重叠碱基个数""" ...

  2. leetcode 题解 (500-1000题,持续更新,part 2)

    part1(1-500), part3(1000-*) 502. IPO 题意:给定k,w,profits数组和capital数组.k表示最多可完成的任务数.w是初始资本.profits是各个任务的收 ...

  3. 创新实训团队记录:为BR-MTC问题设计一个近似算法

    创新实训团队记录 : 为BR-MTC问题设计近似算法 阅读书籍和论文 近似算法设计思路变化总结 算法框架 改变初始顶点集 继续添加路径,作为新的初始顶点集 程序验证 近似解与最优解存在差距&& ...

  4. 如何在编程时屏蔽输入法_取消屏蔽位屏蔽的动态编程

    如何在编程时屏蔽输入法 by Sachin Malhotra 由Sachin Malhotra 取消屏蔽位屏蔽的动态编程 (Unmasking Bitmasked Dynamic Programmin ...

  5. P - The Shortest Path in Nya Graph HDU - 4725

    P - The Shortest Path in Nya Graph HDU - 4725 最短路 不是 每两个点之间按层数设置边权 + 额外边权 TLE 是 相邻两层之间设置边权 + 额外边权 需注 ...

  6. matlab shortest函数,MATLAB函數graphallshortestpaths不返回對稱矩陣

    我正在使用MATLAB函數graphallshortestpaths來計算無向網絡頂點之間的最短路徑.無向網絡作爲加權邊緣列表文件給出,您可以在其中找到here.MATLAB函數graphallsho ...

  7. LeetCode 613. Shortest Distance in a Line --SQL

    LeetCode 613. Shortest Distance in a Line --SQL LeetCode题解专栏:LeetCode题解 我做的所有的LeetCode的题目都放在这个专栏里,大部 ...

  8. OpenJudge/Poj 2001 Shortest Prefixes

    1.链接地址: http://bailian.openjudge.cn/practice/2001 http://poj.org/problem?id=2001 2.题目: Shortest Pref ...

  9. [CF843D]Dynamic Shortest Path

    [CF843D]Dynamic Shortest Path 题目大意: 给定一个带权有向图,包含\(n(n\le10^5)\)个点和\(m(m\le10^5)\)条边.共\(q(q\le2000)\) ...

最新文章

  1. 关于无法创建aps.web项目的解决办法
  2. SpringBoot中的线程池,你真的会用么?
  3. 雷军做程序员时写的博客,太牛了!
  4. 【RocketMQ工作原理】消息堆积与消费延迟
  5. 中国财团收购飞利浦照明业务遭美封杀
  6. 网络之NSURLSession
  7. 【Boost】timer、progress_timer和progress_display
  8. 如果从SVN到GIT
  9. 如何在不跳转的情况下实现用户登录
  10. linux下将编译错误输出到一个文本文件
  11. 打印系统开发(42)——静默打印
  12. html特殊符号拉丁文,拉丁文字符号大全,罗马字母
  13. mysql卸载报错2503_Win10系统卸载Skype软件报错2503的解决方法
  14. linux进程3种状态,进程的三种状态及转换
  15. PHP的WMB队列消费代理的实现
  16. 那些年的 Hello World (HTML)
  17. CentOS7根目录磁盘扩容(/dev/mapper/centos-root 空间不足)
  18. AI智能改写-文本改写人工智能
  19. 免费顺丰快递鸟单号查询不限次数api接口申请步骤
  20. DORIS单节点部署

热门文章

  1. $python数据分析基础——初识numpy库
  2. [置顶] 混响音效
  3. [伤了昨天的心 裂成碎片和沙一起飞]五香里脊
  4. java做报表_一步一步使用POI做java报表
  5. 安卓真机如何连接本地服务器_一分钟搭建可供手机访问的本地服务器 (安卓,ios手机通用)...
  6. 2018计算机河北省高考试题,2018年河北高考物理压轴试题【含答案】
  7. idea的plugins无法使用marketplace plugins are not loaded
  8. ScrollView嵌套ViewPager,ViewPage动态设置高度,嵌套事件冲突——滑动冲突解决方法
  9. 腾讯地图 qq.map 设置鼠标样式
  10. mongoose 定义经纬度数据类型