Javascript 将多个字符串冲压/组合成一个(尽可能短的)字符串,该字符串包含每个字符串正向的所有字符
我的目的是将多个字符串冲压成一个(最短)字符串,该字符串将包含前进方向上每个字符串的所有字符。这个问题不是针对任何语言的,而是更多地涉及到Javascript 将多个字符串冲压/组合成一个(尽可能短的)字符串,该字符串包含每个字符串正向的所有字符,javascript,node.js,algorithm,Javascript,Node.js,Algorithm,我的目的是将多个字符串冲压成一个(最短)字符串,该字符串将包含前进方向上每个字符串的所有字符。这个问题不是针对任何语言的,而是更多地涉及到算法部分。(可能会在节点服务器中实现它,因此标记nodejs/javascript) 因此,要解释这个问题: 让我考虑一下,我有很少的字符串 ["jack", "apple", "maven", "hold", "solid", "mark", "moon", "poor", "spark", "live"] 结果字符串应类似于: "sjmachppoali
算法部分。(可能会在节点服务器中实现它,因此标记nodejs/javascript
)
因此,要解释这个问题:
让我考虑一下,我有很少的字符串
["jack", "apple", "maven", "hold", "solid", "mark", "moon", "poor", "spark", "live"]
结果字符串应类似于:
"sjmachppoalidveonrk"
杰克:sjmachppoalidveonrk
苹果:sjmachppoalidveonrk
固体:sjmachppoalidveonrk
=================================================>>>>>全部在前进方向
这些都是手动评估,示例中的输出可能不是100%完美
因此,关键是每个字符串的所有字母都必须存在于
前进方向(这里是实际问题所在),服务器可能会发送最后的字符串和数字,如27594
,将生成并传递到所需端提取令牌。如果我必须在一个尽可能小的字符串中打孔它,它会变得容易得多(这种情况下,只有唯一的字符就足够了)。但在这种情况下,有以下几点:
信件可以多次出现,但我必须重复使用任何信件
字母,如有可能,例如:对于实心
和保持
o>l>d
可以
重复用作前进方向,但用于apple
(a>p
)和spark
(p>a
)我们必须重复a
,就像在p
对于apple
,对于p
之后的sparks
我们需要重复
a
或p
。甚至,我们也不能做p>a>p
,因为它不能同时涵盖这两种情况
因为我们需要两个p
在a
之后,用于apple
我们直接没有选择放置单个p
并使用相同的
一次提取两次索引,我们需要多个p
,没有选项
左键,因为输入字符串包含
我(不)确定一组数据是否有多个输出
串。但问题是它的长度应该是最小的,
如果组合覆盖了前进方向上的所有令牌,则组合并不重要。最小可能长度的所有(或一个)输出
需要追踪
将此点作为编辑添加到此帖子。在阅读评论并知道它已经存在之后
这个问题是众所周知的
定义结果字符串将是最短的
字符串,我们可以通过简单的
除去一些(0到N)字符,这与在结果字符串中可以找到正向的所有输入相同
我尝试过,从一个任意字符串开始,然后对下一个字符串进行分析,拆分所有字母,并相应地放置它们,但经过一段时间后,如果最后一个字符串(或前一个字符串)的字母是根据当前字符串放置的,则当前字符串的字母可以放置得更好。但同样,字符串是根据处理过的内容(多个)进行分析和放置的,而将未处理的内容置于有利位置似乎很困难,因为要做到这一点,我们需要处理它。或者我可以维护一个包含所有已处理/未处理树的树来帮助构建最终字符串吗?还有比这更好的方法吗,这似乎是一种野蛮的力量
注意:我知道还有很多其他的转换可能,请尽量不要建议使用其他转换,我们正在对此进行一些研究。第一次尝试,没有真正优化(缩短183%):
函数getShort(arr){
var perfect=“”;
//迭代数组
arr.forEach(函数(字符串){
//迭代数组中的字符
string.split(“”).reduce(函数(pos,char){
var n=perfect.indexOf(char,pos+1);//检查是否已经存在可能的char
如果(n我使用了动态规划的思想首先按照OP中的说明在前进方向生成尽可能短的字符串。然后我将上一步获得的结果与列表中的下一个字符串一起作为参数发送。下面是java
中的工作代码。希望这有助于r如果我的解决方案被确定为非最佳解决方案,请随时报告以下代码的任何反例:
public String shortestPossibleString(String a, String b){
int[][] dp = new int[a.length()+1][b.length()+1];
//form the dynamic table consisting of
//length of shortest substring till that points
for(int i=0;i<=a.length();i++){
for(int j=0;j<=b.length();j++){
if(i == 0)
dp[i][j] = j;
else if(j == 0)
dp[i][j] = i;
else if(a.charAt(i-1) == b.charAt(j-1))
dp[i][j] = 1+dp[i-1][j-1];
else
dp[i][j] = 1+Math.min(dp[i-1][j],dp[i][j-1]);
}
}
//Backtrack from here to find the shortest substring
char[] sQ = new char[dp[a.length()][b.length()]];
int s = dp[a.length()][b.length()]-1;
int i=a.length(), j=b.length();
while(i!=0 && j!=0){
// If current character in a and b are same, then
// current character is part of shortest supersequence
if(a.charAt(i-1) == b.charAt(j-1)){
sQ[s] = a.charAt(i-1);
i--;
j--;
s--;
}
else {
// If current character in a and b are different
if(dp[i-1][j] > dp[i][j-1]){
sQ[s] = b.charAt(j-1);
j--;
s--;
}
else{
sQ[s] = a.charAt(i-1);
i--;
s--;
}
}
}
// If b reaches its end, put remaining characters
// of a in the result string
while(i!=0){
sQ[s] = a.charAt(i-1);
i--;
s--;
}
// If a reaches its end, put remaining characters
// of b in the result string
while(j!=0){
sQ[s] = b.charAt(j-1);
j--;
s--;
}
return String.valueOf(sQ);
}
public void getCombinedString(String... values){
String sSQ = shortestPossibleString(values[0],values[1]);
for(int i=2;i<values.length;i++){
sSQ = shortestPossibleString(values[i],sSQ);
}
System.out.println(sSQ);
}
输出:
jmapphsolivecparkonidr
上述解决方案的最坏情况时间复杂度为O(所有输入字符串长度的乘积)
当所有字符串的所有字符都是不同的,并且任何一对字符串之间甚至没有一个字符匹配时。我想出了一种有点暴力的方法。这种方法找到了组合两个单词的最佳方法,然后对数组中的每个元素进行组合
该策略的工作原理是试图找到将两个单词组合在一起的最佳方式。它被认为是具有最少字母的最佳方式。每个单词都被输入一个不断增长的“合并”单词。每次添加新词时,都会搜索要合并的单词中存在的匹配字符。一旦找到一个匹配字符,两个字符将被分成两组并尝试合并(使用现有规则,如果字母已存在,则无需添加两个字符等)。该策略通常会产生良好的结果
join\u word
方法接受两个您希望加入的单词,第一个参数被认为是您希望将另一个放入其中的单词。然后,它搜索spl的最佳方式
var s=["jack",...];
var perfect=null;
for(var i=0;i<s.length;i++){
//shift
s.push(s.shift());
var result=getShort(s);
if(!perfect || result.length<perfect.length) perfect=result;
}
public String shortestPossibleString(String a, String b){
int[][] dp = new int[a.length()+1][b.length()+1];
//form the dynamic table consisting of
//length of shortest substring till that points
for(int i=0;i<=a.length();i++){
for(int j=0;j<=b.length();j++){
if(i == 0)
dp[i][j] = j;
else if(j == 0)
dp[i][j] = i;
else if(a.charAt(i-1) == b.charAt(j-1))
dp[i][j] = 1+dp[i-1][j-1];
else
dp[i][j] = 1+Math.min(dp[i-1][j],dp[i][j-1]);
}
}
//Backtrack from here to find the shortest substring
char[] sQ = new char[dp[a.length()][b.length()]];
int s = dp[a.length()][b.length()]-1;
int i=a.length(), j=b.length();
while(i!=0 && j!=0){
// If current character in a and b are same, then
// current character is part of shortest supersequence
if(a.charAt(i-1) == b.charAt(j-1)){
sQ[s] = a.charAt(i-1);
i--;
j--;
s--;
}
else {
// If current character in a and b are different
if(dp[i-1][j] > dp[i][j-1]){
sQ[s] = b.charAt(j-1);
j--;
s--;
}
else{
sQ[s] = a.charAt(i-1);
i--;
s--;
}
}
}
// If b reaches its end, put remaining characters
// of a in the result string
while(i!=0){
sQ[s] = a.charAt(i-1);
i--;
s--;
}
// If a reaches its end, put remaining characters
// of b in the result string
while(j!=0){
sQ[s] = b.charAt(j-1);
j--;
s--;
}
return String.valueOf(sQ);
}
public void getCombinedString(String... values){
String sSQ = shortestPossibleString(values[0],values[1]);
for(int i=2;i<values.length;i++){
sSQ = shortestPossibleString(values[i],sSQ);
}
System.out.println(sSQ);
}
e.getCombinedString("jack", "apple", "maven", "hold",
"solid", "mark", "moon", "poor", "spark", "live");
spmjhooarckpplivden
const STRINGS = ["jack", "apple", "maven", "hold", "solid", "mark", "moon", "poor", "spark", "live"]
function map(set, f) {
const result = new Set
for (const o of set) result.add(f(o))
return result
}
function addAll(set, other) {
for (const o of other) set.add(o)
return set
}
function shortest(set) { //set is assumed non-empty
let minLength
let minMatching
for (const s of set) {
if (!minLength || s.length < minLength) {
minLength = s.length
minMatching = new Set([s])
}
else if (s.length === minLength) minMatching.add(s)
}
return minMatching
}
class ZipCache {
constructor() {
this.cache = new Map
}
get(str1, str2) {
const cached1 = this.cache.get(str1)
if (!cached1) return undefined
return cached1.get(str2)
}
set(str1, str2, zipped) {
let cached1 = this.cache.get(str1)
if (!cached1) {
cached1 = new Map
this.cache.set(str1, cached1)
}
cached1.set(str2, zipped)
}
}
const zipCache = new ZipCache
function zip(str1, str2) {
const cached = zipCache.get(str1, str2)
if (cached) return cached
if (!str1) { //str1 is empty, so only choice is str2
const result = new Set([str2])
zipCache.set(str1, str2, result)
return result
}
if (!str2) { //str2 is empty, so only choice is str1
const result = new Set([str1])
zipCache.set(str1, str2, result)
return result
}
//Both strings start with same letter
//so optimal solution must start with this letter
if (str1[0] === str2[0]) {
const zipped = zip(str1.substring(1), str2.substring(1))
const result = map(zipped, s => str1[0] + s)
zipCache.set(str1, str2, result)
return result
}
//Either do str1[0] + zip(str1[1:], str2)
//or str2[0] + zip(str1, str2[1:])
const zip1 = zip(str1.substring(1), str2)
const zip2 = zip(str1, str2.substring(1))
const test1 = map(zip1, s => str1[0] + s)
const test2 = map(zip2, s => str2[0] + s)
const result = shortest(addAll(test1, test2))
zipCache.set(str1, str2, result)
return result
}
let cumulative = new Set([''])
for (const string of STRINGS) {
console.log(string)
const newCumulative = new Set
for (const test of cumulative) {
addAll(newCumulative, zip(test, string))
}
cumulative = shortest(newCumulative)
console.log(cumulative.size)
}
console.log(cumulative) //never reached