palindrome, 回文, 正反读都一样的词语
今天是2020年02月02日, 稀有的回文日, 回文题目走你
9. 回文数

思路与代码实现
解法一: 翻转数字
/**
* @param {number} x
* @return {boolean}
*/
var isPalindrome = function(x) {
if (x < 0) {
return false
} else if (x >= 0 && x < 10) {
return true
} else {
let reverse = 0
let cur = x
while (cur / 10 > 0) {
reverse = reverse * 10 + cur % 10
cur = Math.floor(cur / 10)
}
return reverse === x
}
};
优化, 解法二: 翻转半截数字
/**
* @param {number} x
* @return {boolean}
*/
var isPalindrome = function(x) {
// 负数
if (x < 0) {
return false
// 0至9
} else if (x >= 0 && x < 10) {
return true
// 末尾数为0的非零数字
} else if (x !== 0 && x % 10 === 0) {
return false
} else {
let reverse = 0
// 如果翻转数字大于原数字, 则翻转到了中间数位
while (x > reverse) {
reverse = reverse * 10 + x % 10
x = Math.floor(x / 10)
}
// 考虑奇数位
return (reverse === x) || (Math.floor(reverse / 10) === x)
}
};
866. 回文素数

思路与代码实现
验证回文数(参考前面的9. 回文数)和验证素数, 注意不存在八位的素数
/**
* @param {number} N
* @return {number}
*/
var primePalindrome = function(N) {
if (N <= 2) {
return 2
} else {
function isPrime (n) {
let i = 2
while (i <= Math.sqrt(n)) {
if (n % i === 0) {
return false
}
i++
}
return true
}
function isPalindrome (n) {
if (n < 10) {
return true
} else if (n % 10 === 0) {
return false
} else {
let reverse = 0
while (n > reverse) {
reverse = reverse * 10 + n % 10
n = Math.floor(n / 10)
}
return (n === reverse) || (n === Math.floor(reverse / 10))
}
}
while (!(isPalindrome(N) && isPrime(N))) {
N++
if (N > 10000000 && N < 100000000) {
N = 100000000
}
}
return N
}
};
234. 回文链表

思路与代码实现
解法一: 双向链表
把链表变成双向链表, 并从两端向中间比较
复杂度分析
时间复杂度为O(n), 因为要存储prev指针, 所以空间复杂度为O(n)
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @return {boolean}
*/
var isPalindrome = function(head) {
// 考虑空链表
if (head === null) {
return true
} else {
// 头指针
let headPointer = head
// 尾指针
let tailPointer = head
// 把链表变成双向链表
while (tailPointer.next) {
tailPointer.next.prev = tailPointer
tailPointer = tailPointer.next
}
// 分别从头尾向中间依次比较
while(headPointer !== tailPointer) {
if (headPointer.next !== tailPointer) {
if (headPointer.val === tailPointer.val) {
headPointer = headPointer.next
tailPointer = tailPointer.prev
} else {
return false
}
// 考虑偶数链表
} else {
return headPointer.val === tailPointer.val
}
}
return true
}
};
优化, 解法二: 快慢指针
- 慢指针依次访问下一个节点, 并翻转链表
- 快指针依次访问下下一个节点, 直到快指针没有下一个节点(奇数链表)或者下下一个节点(偶数链表), 此时已完成了前半截链表的翻转
- 依次比较前半截链表和后半截链表节点的值
复杂度分析
时间复杂度O(n), 空间复杂度O(1)
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @return {boolean}
*/
var isPalindrome = function(head) {
if (head === null) {
return true
} else if (head.next === null) {
return true
} else {
let slowPointer = head
let fastPointer = head
let _head = null
let temp = null
// 找到中间节点, 并翻转前半截链表,
// 让_head指向翻转后的前半截链表的头部,
// 让slow指向后半截链表的头节点
while (fastPointer && fastPointer.next) {
_head = slowPointer
slowPointer = slowPointer.next
fastPointer = fastPointer.next.next
_head.next = temp
temp = _head
}
// 奇数链表跳过最中间的节点
if (fastPointer) {
slowPointer = slowPointer.next
}
while (_head) {
if (_head.val !== slowPointer.val) {
return false
}
_head = _head.next
slowPointer = slowPointer.next
}
return true
}
};
680. 验证回文字符串 Ⅱ

思路与代码实现
解法一: 双指针
从头尾比较, 若两字符不一相等, 则判断删除某一字符后的子串是否为回文
/**
* @param {string} s
* @return {boolean}
*/
var validPalindrome = function(s) {
let headPointer = 0
let tailPointer = s.length - 1
function isPalindrome (s) {
let headPointer = 0
let tailPointer = s.length - 1
while (headPointer < tailPointer) {
if (s[headPointer] !== s[tailPointer]) {
return false
} else {
headPointer++
tailPointer--
}
}
return true
}
while (headPointer < tailPointer) {
if (s[headPointer] !== s[tailPointer]) {
if (s[headPointer + 1] === s[tailPointer] || s[headPointer] === s[tailPointer - 1]) {
return isPalindrome(s.substring(headPointer + 1, tailPointer + 1)) || isPalindrome(s.substring(headPointer, tailPointer))
} else {
return false
}
} else {
headPointer++
tailPointer--
}
}
return true
};
优化, 解法二: 复用双指针
在解法一的基础上, 不截取子串, 继续利用双指针判断子串是否为回文
/**
* @param {string} s
* @return {boolean}
*/
var validPalindrome = function(s) {
let headPointer = 0
let tailPointer = s.length - 1
function isPalindrome (s, headPointer, tailPointer) {
while (headPointer < tailPointer) {
if (s[headPointer] !== s[tailPointer]) {
return false
} else {
headPointer++
tailPointer--
}
}
return true
}
while (headPointer < tailPointer) {
if (s[headPointer] !== s[tailPointer]) {
if (s[headPointer + 1] === s[tailPointer] || s[headPointer] === s[tailPointer - 1]) {
return isPalindrome(s, headPointer + 1, tailPointer) || isPalindrome(s, headPointer, tailPointer - 1)
} else {
return false
}
} else {
headPointer++
tailPointer--
}
}
return true
};
409. 最长回文串

思路与代码实现
解法一: 哈希表, 判断字符出现的奇偶
/**
* @param {string} s
* @return {number}
*/
var longestPalindrome = function(s) {
const hashTable = {}
let result = 0
for(let i = s.length - 1; i >= 0; --i) {
if (hashTable[s[i]] === undefined) {
hashTable[s[i]] = 1
} else {
++hashTable[s[i]]
}
}
let flag = true
for (let key in hashTable) {
j = hashTable[key]
// 偶数
if ((j & 1) === 0) {
result += j
} else {
// 奇数
result += (j - 1)
if (flag) {
result++
flag = false
}
}
}
return result
};
优化, 解法二: 哈希表, 记录成对的字符
/**
* @param {string} s
* @return {number}
*/
var longestPalindrome = function(s) {
const len = s.length
const hashTable = {}
let result = 0
for(let i = len - 1; i >= 0; --i) {
if (hashTable[s[i]] === undefined || hashTable[s[i]] === 0) {
hashTable[s[i]] = 1
} else {
result += 2
hashTable[s[i]] = 0
}
}
return result < len ? result + 1 : result
};