一、JZ6 从尾到头打印链表(简单)
1、使用栈装
import java.util.ArrayList;
import java.util.Stack;
public class Solution {
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
ArrayList<Integer> list = new ArrayList<Integer>();
Stack<Integer> stack = new Stack<Integer>();
while(listNode != null) {
stack.push(listNode.val);
listNode = listNode.next;
}
while(!stack.empty()) {
list.add(stack.pop());
}
return list;
}
}
2、递归
import java.util.ArrayList;
public class Solution {
//递归函数
public void recursion(ListNode head, ArrayList<Integer> res){
if(head != null){
//先往链表深处遍历
recursion(head.next, res);
//再填充到数组就是逆序
res.add(head.val);
}
}
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
ArrayList<Integer> res = new ArrayList<Integer>();
//递归函数解决
recursion(listNode, res);
return res;
}
}
二、JZ24 反转链表(简单)
1、先使用栈装
import java.util.Stack;
public class Solution {
public ListNode ReverseList(ListNode head) {
Stack<ListNode> stack = new Stack<ListNode>();
while(head != null) {
stack.push(head);
head = head.next;
}
if (stack.empty()) return null;
ListNode listNode = stack.pop();
ListNode result = listNode;
while(!stack.empty()) {
listNode.next = stack.pop();
listNode = listNode.next;
}
listNode.next = null;
return result;
}
}
2、类似双向链表
public ListNode ReverseList(ListNode head) {
//新链表
ListNode newHead = null;
while (head != null) {
//先保存访问的节点的下一个节点,保存起来
//留着下一步访问的
ListNode temp = head.next;
//每次访问的原链表节点都会成为新链表的头结点,
//其实就是把新链表挂到访问的原链表节点的
//后面就行了
head.next = newHead;
//更新新链表
newHead = head;
//重新赋值,继续访问
head = temp;
}
//返回新链表
return newHead;
}
三、JZ25 合并两个排序的链表(简单)
1、创建两个链表,一个用来记录表头返回结果,一个用来完善链表
public class Solution {
public ListNode Merge(ListNode list1,ListNode list2) {
ListNode listNode = null;
ListNode result = null;
if(list1 != null && list2 == null) {
result = list1;
}
if(list1 == null && list2 != null) {
result = list2;
}
if(list1 != null && list2 != null) {
listNode = list1.val < list2.val ? list1 : list2;
result = listNode;
if(list1.val < list2.val) {
list1 = list1.next;
} else {
list2 = list2.next;
}
while(list1 != null) {
if (list2 != null) {
if(list1.val < list2.val) {
listNode.next = list1;
list1 = list1.next;
} else {
listNode.next = list2;
list2 = list2.next;
}
listNode = listNode.next;
} else {
listNode.next = list1;
list1 = list1.next;
listNode = listNode.next;
}
}
while(list2 != null) {
listNode.next = list2;
list2 = list2.next;
listNode = listNode.next;
}
}
return result;
}
}
2、使用递归
public class Solution {
public ListNode Merge(ListNode list1,ListNode list2) {
// list1 list2为空的情况
if(list1 == null || list2 == null){
return list1 != null ? list1 : list2;
}
// 两个链表元素依次对比
if(list1.val <= list2.val){
// 递归计算 list1.next, list2
list1.next = Merge(list1.next, list2);
return list1;
}else{
// 递归计算 list1, list2.next
list2.next = Merge(list1, list2.next);
return list2;
}
}
}
四、JZ52 两个链表的第一个公共结点(简单)
1、将两条链表分别加上另外一条链表,然后进行遍历,然后选择其中一条返回
public class Solution {
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
ListNode listNode1 = pHead1, listNode2 = pHead2;
while (listNode1 != listNode2) {
listNode1 = listNode1 != null ? listNode1.next : pHead2;
listNode2 = listNode2 != null ? listNode2.next : pHead1;
}
return listNode1;
}
}
五、JZ23 链表中环的入口结点(中等)
1、使用HashSet或者ArrayList装,遍历链表并添加到集合,判断是否已添加进集合过
import java.util.HashSet;
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead) {
HashSet<ListNode> hashSet = new HashSet<ListNode>();
while(pHead != null) {
if(hashSet.contains(pHead)) {
return pHead;
}
hashSet.add(pHead);
pHead = pHead.next;
}
return null;
}
}
2、快慢指针
public ListNode EntryNodeOfLoop(ListNode pHead) {
if(pHead == null) return null;
// 定义快慢指针
ListNode slow = pHead;
ListNode fast = pHead;
while(fast != null && fast.next != null){
// 快指针是满指针的两倍速度
fast = fast.next.next;
slow = slow.next;
// 记录快慢指针第一次相遇的结点
if(slow == fast) break;
}
// 若是快指针指向null,则不存在环
if(fast == null || fast.next == null) return null;
// 重新指向链表头部
fast = pHead;
// 与第一次相遇的结点相同速度出发,相遇结点为入口结点
while(fast != slow){
fast = fast.next;
slow = slow.next;
}
return fast;
}
六、JZ22 链表中倒数最后k个结点(简单)
1、用一个数组装起来,然后判断K值与数组的大小关系,执行对应的操作
import java.util.*;
import java.util.ArrayList;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param pHead ListNode类
* @param k int整型
* @return ListNode类
*/
public ListNode FindKthToTail (ListNode pHead, int k) {
// write code here
ArrayList<ListNode> list = new ArrayList<ListNode>();
ListNode listNode = pHead;
while(listNode != null) {
list.add(listNode);
listNode = listNode.next;
}
if(k > list.size()) {
return null;
} else if(k == list.size()){
return pHead;
} else {
int i = list.size() - k;
for(; i> 0; i--) {
pHead = pHead.next;
}
return pHead;
}
}
}
2、快慢指针,快指针先走K步,然后一起next,快指针走完就是结束的标志
import java.util.*;
public class Solution {
public ListNode FindKthToTail (ListNode pHead, int k) {
int n = 0;
ListNode fast = pHead;
ListNode slow = pHead;
//快指针先行k步
for(int i = 0; i < k; i++){
if(fast != null)
fast = fast.next;
//达不到k步说明链表过短,没有倒数k
else
return slow = null;
}
//快慢指针同步,快指针先到底,慢指针指向倒数第k个
while(fast != null){
fast = fast.next;
slow = slow.next;
}
return slow;
}
}
七、JZ35 复杂链表的复制(较难)
1、使用一个map,key跟value都是链表类型,用来存储链表所有的值,后面也用于确定复制链表的值
import java.util.Map;
import java.util.HashMap;
public class Solution {
public RandomListNode Clone(RandomListNode pHead) {
if (pHead == null) return null;
Map<RandomListNode,RandomListNode> map = new HashMap<RandomListNode,RandomListNode>();
RandomListNode listNode = pHead;
while(listNode != null) {
map.put(listNode, new RandomListNode(listNode.label));
listNode = listNode.next;
}
listNode = pHead;
while (listNode != null) {
map.get(listNode).next = map.get(listNode.next);
map.get(listNode).random = map.get(listNode.random);
listNode = listNode.next;
}
return map.get(pHead);
}
}
八、JZ76 删除链表中重复的结点(中等)
1、在链表头部新增一个节点,便于删除表头元素,如果next节点与next.next节点不为null,且值相等,记录当前值,通过while判断一直next到下一个不相等的值,如果值不等则直接next下一个值
public class Solution {
public ListNode deleteDuplication(ListNode pHead) {
if(pHead == null) return null;
ListNode listNode = new ListNode(0);
listNode.next = pHead;
ListNode result = listNode;
while(listNode.next != null && listNode.next.next !=null) {
if(listNode.next.val == listNode.next.next.val) {
int temp = listNode.next.val;
while(listNode.next != null && listNode.next.val == temp) {
listNode.next = listNode.next.next;
}
} else {
listNode = listNode.next;
}
}
return result.next;
}
}
2、使用map记录各节点值出现次数,在链表头部新增一个节点,便于删除表头元素,再次遍历链表,只保留出现次数为1的
import java.util.*;
public class Solution {
public ListNode deleteDuplication(ListNode pHead) {
//空链表
if(pHead == null)
return null;
Map<Integer,Integer> mp = new HashMap<>();
ListNode cur = pHead;
//遍历链表统计每个节点值出现的次数
while(cur != null){
if(mp.containsKey(cur.val))
mp.put(cur.val, (int)mp.get(cur.val) + 1);
else
mp.put(cur.val,1);
cur = cur.next;
}
ListNode res = new ListNode(0);
//在链表前加一个表头
res.next = pHead;
cur = res;
//再次遍历链表
while(cur.next != null){
//如果节点值计数不为1
if(mp.get(cur.next.val) != 1)
//删去该节点
cur.next = cur.next.next;
else
cur = cur.next;
}
//去掉表头
return res.next;
}
}
九、JZ18 删除链表的节点(简单)
1、在链表头部新增一个节点,便于删除表头元素,遍历链表,判断next值是否等于给定的值,相等的话,next = next.next来跳过值相等的节点
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param head ListNode类
* @param val int整型
* @return ListNode类
*/
public ListNode deleteNode (ListNode head, int val) {
// write code here
if(head == null) return null;
ListNode listNode = new ListNode(0);
listNode.next = head;
ListNode result = listNode;
while(listNode.next != null) {
if(listNode.next.val == val) {
listNode.next = listNode.next.next;
} else {
listNode = listNode.next;
}
}
return result.next;
}
}