1.从尾到头打印链表
解法1:栈
解题思路:
- 将节点元素压入栈中
- 将栈中元素弹出,依次放入数组,返回数组
class Solution {
public int[] reversePrint(ListNode head) {
Stack<ListNode> stack=new Stack<>();
while (head!=null){
stack.push(head);
head=head.next;
}
int[] array=new int[stack.size()];
for (int i = 0; i < array.length; i++) {
array[i]=stack.pop().val;
}
return array;
}
}
解法2:反转链表
解题思路:
- 用链表反转函数将链表反转
- 遍历新的链表,将链表的值依次放入数组
- 还原链表,返回数组
链表反转函数:
public ListNode reverseList(ListNode head) {
ListNode cur=head;
ListNode pre=null;
while (cur!=null){
head=head.next;
cur.next=pre;
pre=cur;
cur=head;
}
return pre;
}
主函数:
ps:这函数一点都不好,下一个。
public int[] reversePrint1(ListNode head) {
head = reverseList(head);
ListNode cur=head;
ArrayList<Integer> list=new ArrayList<>();
while (cur!=null){
list.add(cur.val);
cur=cur.next;
}
int[] array=new int[list.size()];
int i=0;
while (!list.isEmpty()){
array[i++]=list.remove(i);
i++;
}
head=reverseList(head);
return array;
}
解法3:遍历大法
解题思路:
- 第一遍遍历找出链表长度,第二遍遍历直接给数组赋值
- 返回数组
public static int[] reversePrint(ListNode head) {
ListNode node = head;
int count = 0;
while (node != null) {
++count;
node = node.next;
}
int[] nums = new int[count];
node = head;
for (int i = count - 1; i >= 0; --i) {
nums[i] = node.val;
node = node.next;
}
return nums;
}
2.链表反转
解法1:栈
解题思路:
- 利用栈的特性,压栈,弹栈,很简单
public ListNode reverseList_stack(ListNode head) {
if (head == null) return head;
Stack<ListNode> stack = new Stack<>();
while (head!=null){
stack.push(head);
head = head.next;
}
ListNode newHead = stack.pop();
ListNode tailNode = newHead;
while (!stack.isEmpty()){
ListNode cur = stack.pop();
tailNode.next = cur;
tailNode = cur;
}
tailNode.next = null;
return newHead;
}
解法2:头插法
解题思路:
while循环
头节点下移,
cur节点的next指pre节点,
pre节点下移,
cur节点找到头节点head
public ListNode reverseList(ListNode head) {
ListNode cur=head;
ListNode pre=null;
while (cur!=null){
head=head.next;
cur.next=pre;
pre=cur;
cur=head;
}
return pre;
}
解法3:递归
递归与方法1原理相似,利用系统栈,实现链表反转
3.复杂链表的复制
解法1:HashMap
思路:
- 若头节点 head 为空节点,直接返回null ;
- 初始化: 哈希表 map, 节点 cur 指向头节点;
- 复制链表:
建立新节点,并向 map添加键值对 (原 cur 节点, 新 cur 节点) ;
cur 遍历至原链表下一节点; - 构建新链表的引用指向:
构建新节点的 next 和 random 引用指向; - cur 遍历至原链表下一节点;
返回值: 新链表的头节点 map[head] ;
HashMap<Node,Node> nextMap=new HashMap<>();
Node cur=head;
while (cur!=null){
nextMap.put(cur, new Node(cur.val));
cur=cur.next;
}
cur=head;
while (cur!=null){
nextMap.get(cur).next=nextMap.get(cur.next);
nextMap.get(cur).random=nextMap.get(cur.random);
cur=cur.next;
}
return nextMap.get(head);
解法2:相对位置克隆
解法:
- 克隆原节点
- 对照相对位置,克隆random
- 将链表拆分,得到新链表
n1->n1’->n2->n2’->null
public Node copyRandomList(Node head) {
if(head == null) return null;
Node cur = head;
// 1. 复制各节点,并构建拼接链表
while(cur != null) {
Node tmp = new Node(cur.val);
tmp.next = cur.next;
cur.next = tmp;
cur = tmp.next;
}
// 2. 构建各新节点的 random 指向
cur = head;
while(cur != null) {
if(cur.random != null)
cur.next.random = cur.random.next;
cur = cur.next.next;
}
// 3. 拆分两链表
cur = head.next;
Node pre = head, res = head.next;
while(cur.next != null) {
pre.next = pre.next.next;
cur.next = cur.next.next;
pre = pre.next;
cur = cur.next;
}
pre.next = null; // 单独处理原链表尾节点
return res;
}