我需要构建一个算法(不一定有效),给定一个字符串找到并打印两个相同的子序列(通过打印,我的意思是颜色).此外,这两个子序列的索引集合的联合必须是一组连续的自然数(整数的整数).
在数学中,我正在寻找的东西被称为“紧身双胞胎”,如果它有帮助的话. (例如,参见paper (PDF) here.)
我举几个例子:
1)考虑字符串231213231
它有两个子序列,我正在寻找“123”的形式.要更好地查看此图片:
第一个子序列标有下划线,第二个子序列标有上划线.如你所见,他们拥有我需要的所有属性.
2)考虑字符串12341234
3)考虑字符串12132344.
现在它变得更加复杂:
4)考虑字符串:13412342
它也不是那么容易:
我认为这些例子很好地解释了我的意思.
我一直在思考一个可以做到这一点但却没有成功的算法.
为了着色,我想使用这段代码:
using namespace std; HANDLE hConsole; hConsole = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleTextAttribute(hConsole,k);
其中k是颜色.
任何帮助,甚至提示,都将受到高度赞赏.
解决方法
这是一个简单的递归,测试紧身双胞胎.当存在重复时,它会拆分决策树,以防副本仍然是第一个双胞胎的一部分.你必须在偶数长度的每个子串上运行它.对较长子串的其他优化可能包括对char计数进行散列测试,以及匹配候选双胞胎的非重复部分(仅在整个子字符串中出现两次的字符).
功能说明:
首先,创建一个散列,每个字符作为键,索引以值的形式出现.然后我们遍历哈希:如果字符计数是奇数,则该函数返回false;并且计数大于2的字符的索引被添加到重复列表中 – 其中一半字符属于一个双胞胎,但我们不知道哪个.
递归的基本规则是仅在字符串中稍后找到匹配时增加i,同时保持所选匹配(js)的记录,我必须跳过该记录而不查找匹配.这是有效的,因为如果我们找到n / 2个匹配,按顺序,到j到达结尾时,这基本上只是另一种说法是字符串由紧孪生组成的方式.
JavaScript代码:
function isTightTwins(s){ var n = s.length,char_idxs = {}; for (var i=0; i<n; i++){ if (char_idxs[s[i]] == undefined){ char_idxs[s[i]] = [i]; } else { char_idxs[s[i]].push(i); } } var duplicates = new Set(); for (var i in char_idxs){ // character with odd count if (char_idxs[i].length & 1){ return false; } if (char_idxs[i].length > 2){ for (let j of char_idxs[i]){ duplicates.add(j); } } } function f(i,j,js){ // base case positive if (js.size == n/2 && j == n){ return true; } // base case negative if (j > n || (n - j < n/2 - js.size)){ return false; } // i is not less than j if (i >= j) { return f(i,j + 1,js); } // this i is in the list of js if (js.has(i)){ return f(i + 1,js); // yet to find twin,no match } else if (s[i] != s[j]){ return f(i,js); } else { // maybe it's a twin and maybe it's a duplicate if (duplicates.has(j)) { var _js = new Set(js); _js.add(j); return f(i,js) | f(i + 1,_js); // it's a twin } else { js.add(j); return f(i + 1,js); } } } return f(0,1,new Set()); } console.log(isTightTwins("1213213515")); // true console.log(isTightTwins("11222332")); // false