今天我有一个非常有趣的采访问题:
给定一个字符串,你必须确定该字符串在置换时是否可以有回文。
以下是我提出的实施方案。但是有更好的解决方案吗?
function canBePalindrome(someStr) {
if (typeof someStr !== "string") {
throw new Error("Expecting argument to be a string !");
}
if (someStr.length == 1) return someStr;
var canBePalin = false;
var _chunks = someStr.split("");
var _length = _chunks.length;
for (var i = 0; i < _length; i++) {
for (var j = i + 1; j < _length; j++) {
var temp_char = _chunks[i];
_chunks[i] = _chunks[j];
_chunks[j] = temp_char;
if (isPalindrome(_chunks.join(""))) return true;
}
}
return canBePalin;
} //End of canBePalindrome
function isPalindrome(someStr) {
//console.log("Checking for:"+someStr);
var original = someStr.split("");
return someStr === original.reverse().join("");
} //End of isPalindrome
canBePalindrome("mdadm");
这不可能重复,因为我不是直接检查它是否是回文,而是检查和检查它。
答案 0 :(得分:6)
保留一个字符地图,计算它们,并查看所有字符的计数是否均匀,如果是,则可以创建回文
function canBePalindrome(someStr) {
var map = {};
var arr = someStr.split('');
arr.forEach(function(s) {
s in map ? map[s]++ : map[s] = 1;
});
var len = Object.keys(map).filter(function(o) {
return map[o] % 2;
}).length;
return arr.length % 2 ? len === 1 : len === 0;
}
以上的“高尔夫”版本将是
function canBePalindrome(someStr) {
return (function(m, a, l) {
a.forEach(function(s) { s in m ? m[s]++ : m[s] = 1 });
l = Object.keys(m).filter(function(o) { return m[o] % 2 }).length;
return a.length % 2 ? l === 1 : l === 0;
})({}, someStr.split(''));
}
答案 1 :(得分:3)
如果字符串中的所有字母都具有偶数,除了最多一个,您始终可以将它们重新组织成回文。我的解决方案比其他解决方案稍长,因为我试图最小化带有函数和不必要的数组创建的循环的性能开销。
aaaabbbb => aabbbbaa
aaaabbbbc => aabbcbbaa
function isPalindromable(str) {
var map = getCharCount(str);
var nonPairs = 0;
for (var char in charMap) {
if (charMap[char] % 2 != 0)
nonPairs++;
if (nonPairs > 1)
return false;
}
return true;
}
function getCharCount(str) {
// Number of times each string appeared
var map = {};
for (var i = 0; i < str.length; i++) {
var ch = str.charAt(i);
map[ch] = ++map[ch] || 1;
}
return map;
}
如果您喜欢一个衬垫(不是那么快,而是优雅)
function isPalindromable(str) {
var charMap = getCharCountMap(str);
return Object.keys(charMap).filter(char => charMap[char] %2 > 0).length <= 1;
}
function getCharCountMap(str) {
return str.split('').reduce((prev, cur) => (prev[cur] = ++prev[cur] || 1, prev) , {})
}
效果编辑
我对三种解决方案进行了基准测试。当琴弦很短时,我的速度最慢,而对于较长的琴弦,最快。然而,一位工作的朋友想出了一个最快速的解决方案,可能是因为它只有一个循环但不需要排序。 http://jsperf.com/can-string-be-made-into-palindrome/2
function canBePalindromeReplace(string) {
var oddCount = 0;
while(string.length > 0) {
var char = string.charAt(0);
var stringLength = string.length;
string = string.replace(new RegExp(char, 'g'), '');
var diff = stringLength - string.length;
if((diff % 2) != 0) {
oddCount++;
if(oddCount > 1) {
return false;
}
}
}
return true;
}
答案 2 :(得分:1)
使用排序和堆栈的解决方案:
function canBePalindrome(someStr) {
var stack = [];
someStr.split('').sort().forEach(function(ch) {
stack[stack.length - 1] === ch ? stack.pop() : stack.push(ch);
});
return stack.length < 2;
}
答案 3 :(得分:0)
一个很好的技巧是看到回文的以下属性:
使用此信息,您可以编写一个算法来计算字符串中每个可能的char出现的次数,然后查看是否符合以前的属性。此算法应具有O(N + M)
时间复杂度,其中N是字符串的大小,M是字符串中可能出现的字符数量。例如,如果字符串只有ASCII字符,则时间复杂度为O(N + 255)
。空间复杂度为O(N + M)
。
答案 4 :(得分:0)
我认为更好的方法是创建一个长度为26的数组arr[26]
。每个字母一个。然后通过字符串增加每个字母发生的频率。
完成后,请查看arr[]
并检查所有频率是否均匀。只有一个奇数频率的字符,我们可以把它放在回文的中间。
如果所有频率均匀,那么它可以组织成回文。
否则不是。
算法看起来应该是这样的
str[] holding the string;
create arr[26] and intialize with 0;
for char in str:
arr[char]++ //char should be mapped to its index properly
// like a = 0, b = 1 and so on
no_of_odd_char = 0
for freq in arr:
if(freq % 2 == 1)
if(no_of_odd_char == 1)
print "cannot be palindrome"
exit()
else if(no_of_odd_char == 0)
no_of_odd_char = 1
print "can be palindrome"
答案 5 :(得分:0)
如果出现奇数次的字符数为0或1,则存在字符串的排列。
int main() {
int* p; // p is at address #1 and the value uninitialized. p will
// be at address #1 throughout the whole program.
// It is only the value of p that can change.
p = new int(6); // The value of p is set to address #2 and your
// program now has ownership of sizeof(int) bytes
// starting from address #2. The int at address #2
// is initialized with the value 6.
cout << *p << endl;
delete p; // Your program releases ownership of the memory at
// address #2 and you are not allowed to use it anymore.
// The value of p is undefined.
return 0;
}
您可以使用function canBePalindrome(str) {
var isOdd = Object.create(null),
numOdd = 0;
for(let ch of str)
numOdd += (isOdd[ch] = !isOdd[ch]) * 2 - 1;
return numOdd <= 1;
}
进行迭代以支持ES6之前的实现,但如果字符串包含超出代码点范围前16位的unicode代码点,则无法正常工作。