labuladong算法公众号学习笔记
labuladong算法公众号学习笔记
labuladong算法公众号学习笔记
单链表的结构:
//单链表节点的结构
public class ListNode{
int val;
ListNode nest;
ListNode(int x) {val=x;}
}
递归反转整个链表
实现代码如下:
ListNode reverse(ListNode head){
if(head.next == null) return head;
ListNode last = reverse(head.next);
head.next.next = head;
head.next = null;
return last;
}
对于递归算法,最重要的是明确递归函数的定义。
对于reverse函数:输入一个节点head,将[以Head为起点]的链表反转,并返回反转之后的头节点。
需要注意的地方有两个点:
1、递归函数要有base case。
2、当链表递归反转之后,新的头节点是last,而之前的head变成了最后一个节点,链表的末尾指针要指向Null。
反转链表前N个节点
思路同上:
ListNode successor = null;
ListNode reverseN(ListNode head,int n){
if(n == 1){
successor = head.next;
return head;
}
//以head.next为起点,需要反转前n-1个节点
ListNode last = reverseN(head.next,n-1);
head.next.next = head;
//让反转之后的head节点和后面的节点连起来
head.next = successor;
return last;
}
具体区别:
1、base case变为n == 1,反转一个元素,就是其本身,同时要记录后驱节点。
2、现在head节点在递归反转之后不一定是最后一个节点,所以要记录后驱successor(第n+1个节点),反转之后将head连接上。
反转链表的一部分
给一个索引区间[m,n],仅仅反转区间中的链表元素。
1、如果m==1,就相当于反转链表开头的n个元素。
2、如果m!=1,把head索引视为1,从第m个元素开始反转;把head.next的索引视为1,反转的区间从第m-1个元素开始;…(递归思想)
ListNode reverseBetween(ListNode head,int m,int n){
//base case
if(m == 1){
return reverseN(head,n);
}
//前进到反转的起点触发 base case
head.next = reverseBetween(head.next,m-1,n-1);
return head;
}
总结
递归处理的技巧是:不要跳进递归,而是利用明确的定义来实现算法逻辑。
处理比较困难的问题,可以尝试化整为零,把一些简单的解法进行修改。