给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。
回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。例如,121 是回文,而 123 不是。
示例 1:
输入:x = 121
输出:true
来源:力扣(LeetCode)
进阶:你能不将整数转为字符串来解决这个问题吗?
看见题目的第一眼就是转成字符串或者数组,然后刷刷的的写了字符串的,发现,速度和内存使用排名都特别低,有点纳闷,看了题解才想到,如果数字是回文数,那么它反转的数字也等于原数字,而且 我们甚至不需要全部反转,只需要反转一半就行了
这题需要注意三点
一:
数字后缀为0 ,10 , 100 , 110这种,最后x = 0,rx = 1,虽然不直接相等,但是rx/10 = 0了。满足这个条件,显然这不是我们想要的结果,因此必须提前剔除掉
当然还有负数也是不可能为回文的,0本身的话是没问题的
二:
数字长度为奇数,这种情况就 if ( x == rx/10 )
三:
数字长度为偶数, if ( x == rx )
class Solution {
public:
bool isPalindrome(int x) {
//排除特殊情况1
if(x < 0 || (x!=0 && x%10 == 0)) return false;
int rx = 0;
while(rx < x)//只需要反转一半
{//反转并缩减x
rx = rx*10 + x%10;
x /= 10;
}
return rx == x || rx/10 == x;//判断奇偶数两种情况
}
};
给你一个字符串 s,找到 s 中最长的回文子串。
示例 1:
输入:s = “babad”
输出:“bab”
解释:“aba” 同样是符合题意的答案。
来源:力扣(LeetCode)
思路:
中心扩展,
从左往右遍历字符串,把每个字符串以及每对相邻字符串都当成回文字符串的中心
然后用子程序求出每个中心的回文长度,然后维护一个最大长度maxlen,再维护两个指针start , end ,每次maxlen更新最大值时,就接着更新两指针的位置
最后,遍历完以后,以start为依据,maxlen为长度,提取子字符串返回
求长度子程序的思路:
我们传入字符串的引用和中心,中心用两个变量(left , right)确定,如果是要求奇数长度,就left = right , 偶数长度就 right = left + 1
然后依次比较中心两端的字符,如果相等就扩展,继续比较,不相等或者两端到达了原字符串的边界,就返回长度,
这里要注意一下:字符串下标越界的可能性
所以我们利用&&的短路特性,把边界条件写前面,匹配条件写后边,这样如果到达边界就会直接返回,不会再去对中心两端的字符串做匹配,也就不会越界
第二点:
left 和 right 扩展到最后,其实是在回文子字符串的外边的,不是指向字符串两端,所以回文子字符串长度不是 right - left + 1 ,而是 right - left - 1
代码:
class Solution {
public:
int count (const string& s , int left , int right)
{//利用&&得短路特性防止越界并简化代码
while(left >= 0 && right <s.size() && s[left] == s[right])
{
left--;//扩展
right++;
}
return right-left-1;//返回正确的长度
}
string longestPalindrome(string s) {
int N = s.size();
if(N == 0 || N == 1) return s;//
int maxlen = 0, start = 0, end = 0;
for(int i = 0;i<N;++i)
{
int len1 = count(s,i,i);//奇数中心
int len2 = count(s,i,i+1);//偶数中心
//维护最大回文子字符串长度
maxlen = max(max(len1,len2),maxlen);
//这里就是维护start 和 end
if(maxlen > end - start + 1)
{
end = i + maxlen /2;
start = end - maxlen + 1;
}
}
return s.substr(start,maxlen);
}
};
234. 回文链表
请判断一个链表是否为回文链表。
示例 :
输入: 1->2
输出: false
进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
如果不要求空间复杂度的话,直接转成数组就很快,既然有要求,就只能沿用文章第一题的思路了,一个回文,分成两半,一半的翻转肯定等于另一半
**思路:**找中点的同时求链表长度,然后从中点把后半部分翻转,再与前半部分比较,如果有不相等的就说明不是回文
这里注意一下,我们已经算出了链表长度,所以不管链表长度是奇数还是偶数,只要对两个子链表进行 size/2 次比较即可
代码:
class Solution {
ListNode* reverse(ListNode*start)
{
ListNode*cur = start, *pre = nullptr;//翻转链表的程序
while(cur)
{
ListNode*next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}
public:
bool isPalindrome(ListNode* head) {
int size = 0;
ListNode* head1 = head, *mid = head;
while(head1)
{//找到中点并求长度,如果是两个中点,就定位到右边
head1 = head1->next;++size;
if(!head1) break;
head1 = head1->next;++size;
mid = mid->next;
}
head1 = head;
ListNode*head2 = reverse(mid);
for(int i = 0;i<size/2;++i)
{//将两个子链表比较size/2次
if(head1->val != head2->val) return false;//一旦发现不一样的就说明不是回文
head1 = head1->next;head2 = head2->next;
}
return true;
}
};