定义函数 CreateLinkedList,让其返回值为 Node(链表头),每次必须缩小问题规模且必须为1;则将 1 拆掉,把 2、3、4、5 添入到
CreateLinkedList,再把 1 和 2、3、4、5 连接起来即可;
如何接:把 1 的 next 和 2、3、4、5 的 head 接起来就完成了链表的创建;
代码实现:
Node.java[创建节点]
package interview.common;
public class Node {
private final T value; //用户传入不能再做改变,设置final
private Node next;
public Node(T value) {
this.value = value;
this.next = null;
}
public T getValue() {
return value;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
public static void printLinkedList(Node head) {
while(head != null) {
System.out.print(head.getValue());
System.out.print(" ");
head = head.getNext();
}
System.out.println();
}
}
LinkedListCreator.java
package interview.recursion;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import interview.common.Node;
public class LinkedListCreator {
/**
* Creates a linked list.
*
* @param data the data to create the list
* @return head of the linked list. The returned linked list
* ends with last node with getNext() == null.
*/
public Node createLinkedList(List data) { //定义函数,参数为List
if (data.isEmpty()) { //链表为空时【特殊】
return null;
}
Node firstNode = new Node<>(data.get(0)); //将 node 第0个元素拿出来新建 node
firstNode.setNext(
createLinkedList(data.subList(1, data.size())));
//用头结点接收去掉第0个元素剩下的所有元素【把 1 的 next 和 2、3、4、5 的 head 接起来就完成了链表的创建】
return firstNode;
}
public Node createLargeLinkedList(int size) {
Node prev = null;
Node head = null;
for (int i = 1; i <= size; i++) {
Node node = new Node<>(i);
if (prev != null) {
prev.setNext(node);
} else {
head = node;
}
prev = node;
}
return head;
}
public static void main(String[] args) {
LinkedListCreator creator = new LinkedListCreator();
Node.printLinkedList(
creator.createLinkedList(new ArrayList<>()));
Node.printLinkedList(
creator.createLinkedList(Arrays.asList(1)));
Node.printLinkedList(
creator.createLinkedList(Arrays.asList(1, 2, 3, 4, 5)));
}
}
输出:
由上图到下图
思路:
1.将问题的规模减小,减小的量为 1,先将 2、3、4、5 这个链表反转了
2.假设可以正确反转,得图
3.假设 2 开头的链表已经进行了正确的反转,要使得 1 这个链表也要能真确的反转,将 2 的 Next 也指向 1;
4. 1 的 Next 指向 Null;至此,链表反转完成;
代码实现:
LinkedListReverser.java
package interview.recursion;
import java.util.ArrayList;
import java.util.Arrays;
import interview.common.Node;
public class LinkedListReverser {
/**
* Reverses a linked list.
*
* @param head the linked list to reverse
* @return head of the reversed linked list
*/
public Node reverseLinkedList(Node head) {
// size == 0 or size == 1
if (head == null || head.getNext() == null) { //链表为空或1
return head;
}
Node newHead = reverseLinkedList(head.getNext()); //(假设)将head.getNext()开头的LinkedList 反转
head.getNext().setNext(head); //将第二个 head.next 由指向 null 变为指向自己
head.setNext(null); //将自己的head.next指向null
return newHead; //返回指向 5 的节点
}
public static void main(String[] args) { //测试代码
LinkedListCreator creator = new LinkedListCreator();
LinkedListReverser reverser = new LinkedListReverser();
Node.printLinkedList(reverser.reverseLinkedList(
creator.createLinkedList(new ArrayList<>())));
Node.printLinkedList(reverser.reverseLinkedList(
creator.createLinkedList(Arrays.asList(1))));
Node.printLinkedList(reverser.reverseLinkedList(
creator.createLinkedList(Arrays.asList(1, 2, 3, 4, 5))));
System.out.println("Testing large data. Expect exceptions.");
reverser.reverseLinkedList(
creator.createLargeLinkedList(1000000));
System.out.println("done");
}
}
输出:
缩小规模:1.从 [1,2,3,4] 中取出 2 个元素进行组合;2.对第一个元素有两个选择:要它或者不要它;
选 1:从[2,3,4] 中选择 1 个元素;
不选1:从[2,3,4] 中选择 2个元素;完成递推关系
代码:Combinations.java
package interview.recursion;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Combinations {
/**
* Generates all combinations and output them,
* selecting n elements from data.
*/
public void combinations(
List selected, List data, int n) {
if (n == 0) {//从集合中选择0个元素
// output all selected elements
for (Integer i : selected) {
System.out.print(i);
System.out.print(" ");
}
System.out.println();
return;
}
if (data.isEmpty()) { //从空集中选择0个元素【1种】
return;
}
// select element 0[选择第0号元素]
selected.add(data.get(0)); //添加第0个元素
combinations(selected, data.subList(1, data.size()), n - 1);
// un-select element 0[不选择第0号元素]
selected.remove(selected.size() - 1); //删掉最后一个元素
combinations(selected, data.subList(1, data.size()), n);
}
public static void main(String[] args) {
Combinations comb = new Combinations();
System.out.println("Testing normal data.");
comb.combinations(
new ArrayList<>(), Arrays.asList(1, 2, 3, 4), 2);
System.out.println("==========");
System.out.println("Testing empty source data.");
comb.combinations(
new ArrayList<>(), new ArrayList<>(), 2); //空集里选出2个元素
System.out.println("==========");
comb.combinations(
new ArrayList<>(), new ArrayList<>(), 0);//空集里选出0个元素
System.out.println("==========");
System.out.println("Selecting 1 and 0 elements.");
comb.combinations(
new ArrayList<>(), Arrays.asList(1, 2, 3, 4), 1); //从(1, 2, 3, 4)中选出1个元素
System.out.println("==========");
comb.combinations(
new ArrayList<>(), Arrays.asList(1, 2, 3, 4), 0);
System.out.println("==========");
}
}
输出:
1.函数调用开销
2.每一次调用节点都会调用栈、超出栈的范围,会发生 Stack Overflow;