1.反转链表
使用递归的方法,对于递归算法,最重要的就是明确递归函数的定义。具体来说,我们的reverse函数定义是这样的:输入一个节点head,将「以head为起点」的链表反转,并返回反转之后的头结点, 显然如果将head->next作为参数执行,就会将以head->next为头节点的链表反转,而头节点没有被反转。之后只要将头节点反转就可以了
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(!head || !head->next) return head;
ListNode* newHead = reverseList(head->next);
head->next->next = head;
head->next = nullptr;
return newHead;
}
};
2.反转链表 II
这题是上面题的变式,该题只需反转部分链表
同样也是递归, 要解决该题先解决反转链表前n个节点的问题。
思路和反转整个链表差不多,只要稍加修改1、递归出口,变为n == 1 2.之前head->next直接为空,因为后面所有节点都反转了,只剩下头节点了,但是现在head节点不一定是最后一个节点了,所以要记录后驱节点 successor (第 n + 1 个节点), 反转后将head 接上
反转链表前n个节点
ListNode* successor;
ListNode* reverseN(ListNode* head, int n){
if(n == 1){
successor = head->next;
return head;
}
ListNode* newHead = reverseN(head->next, n - 1);
head->next->next = head;
head->next = successor;
return newHead;
}
现在来解决这个题目, 反转区间 [m , n] (m 从 1 开始)的节点。
首先如果m == 1 ,那不就相当于反转链表前n个元素嘛
那么 m != 1时, 如果把head 的索引视为1, 那么我们是想从第 m 个元素开始反转对吧;如果把head->next 的索引视为1呢?那么反转的区间应该时从 m - 1个元素开始的;那么对与head->next->next呢…
这就是递归思想,代码如下
class Solution {
public:
ListNode* successor;
ListNode* reverseN(ListNode* head, int n){
if(n == 1){
successor = head->next;
return head;
}
ListNode* newHead = reverseN(head->next, n - 1);
head->next->next = head;
head->next = successor;
return newHead;
}
ListNode* reverseBetween(ListNode* head, int left, int right) {
if(left == 1){
return reverseN(head, right);
}
head->next = reverseBetween(head->next, left-1, right-1);
return head;
}
};
3. K个一组翻转链表
之前的题目都是用递归来写的,这个用迭代的方法来解
1.先翻转以 head 开头的 k 个元素
2.将第 k + 1 个元素作为 head 递归调用 reverseKGroup 函数
3. 将上述两个结果连接起来
翻转区间 [ a, b)的节点 注意是左闭右开
ListNode* reverse(ListNode*a, ListNode*b){
ListNode* pre;
ListNode* cur;
ListNode* nxt;
pre = nullptr; cur = a;nxt = a;
while(cur != b){
nxt = cur->next;
cur->next = pre;
pre = cur;
cur = nxt;
}
return pre;
}
reverserKGroup 函数代码如下:
ListNode* reverseKGroup(ListNode* head, int k) {
if(!head) return nullptr;
ListNode* a;
ListNode* b;
b = head;
a = head;
for(int i = 0; i < k; i++){
// 不足 k 个, 不需要翻转
if(!b) return head;
b = b->next;
}
// 翻转前 k 个节点
ListNode* newHead = reverse(a, b);
// 递归反转后续链表并连接起来
a->next = reverseKGroup(b, k);
return newHead;
}
4.最长回文字串
寻找回文串的问题核心思想是:从中间开始向两边扩散来判断回文串
但是呢,回文串的长度可能是奇数也可能是偶数,如果是abba这种情况,没有一个中心字符,所以我们可以修改一下:
for 0 <= i < len(s):
找到以 s[i] 为中心的回文串
找到以 s[i] 和 s[i+1] 为中心的回文串
更新答案
但这样做,索引会越界,等会会处理
先实现一个函数来寻找最长回文串,这个函数是有点技巧的
传入两个指针 l 和 r , 可以同时处理回文串长度为奇数和偶数的情况
string findlongest(string s, int l, int r){
// 防止索引越界
while(l >= 0 && r < s.length() && s[l] == s[r]){
l--;
r++;
}
return s.substr(l + 1, r - l - 1 );
}
最终代码:
string longestPalindrome(string s) {
string res;
for(int i = 0; i < s.size(); i++){
string s1 = findlongest(s,i, i);
string s2 = findlongest(s, i, i + 1);
res = res.size() > s1.size()? res:s1;
res = res.size() > s2.size()? res:s2;
}
return res;
}