链表题目总结
1. 从尾到头打印链表
思路: 使用递归
import java.util.ArrayList;
public class Solution {
// 定义在外部,以防递归的时候被覆盖
ArrayList<Integer> ret = new ArrayList<>();
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
if(listNode==null) return ret;
printListFromTailToHead(listNode.next);
ret.add(listNode.val);
return ret;
}
}
2. 链表中倒数第K个结点
思路:双指针,其中一个指针先走k-1步,到达k的位置。然后两个指针通知走,直到前面的指针指向最后一个元素,然后提取后面的节点
public class Solution {
public ListNode FindKthToTail(ListNode head,int k) {
ListNode i = head;
ListNode j = head;
if(k<=0 || head == null){
return null;
}
for(int v=1; v<k; v++){
j = j.next;
// 注意,k的范围可能超过
if(j==null) return null;
}
while(j.next!=null){
i = i.next;
j = j.next;
}
return i;
}
}
3.反转链表
思路:
非递归做法
public class Solution {
public ListNode ReverseList(ListNode head) {
if(head==null||head.next==null) return head;
ListNode preNode = null;
ListNode curNode = head;
while(curNode != null){
ListNode nextNode = curNode.next;
curNode.next = preNode;
preNode = curNode;
curNode = nextNode;
}
return preNode;
}
}
递归做法
public class Solution {
public ListNode ReverseList(ListNode head) {
if(head==null||head.next==null) return head;
// 递归到倒数第二个元素
ListNode reverseHead = ReverseList(head.next);
head.next.next = head;
head.next = null;
return reverseHead;
}
}
4.合并两个排序的链表
思路:
非递归做法
public class Solution {
public ListNode Merge(ListNode list1,ListNode list2) {
// 保存头结点
ListNode newList = null;
// 保存当前遍历的结点
ListNode current = null;
if(list1==null) return list2;
if(list2==null) return list1;
while(list1!=null&&list2!=null)
if(list1.val<=list2.val){
if(newList==null){
newList = list1;
current = newList;
}
else{
current.next = list1;
current = current.next;
}
list1 = list1.next;
}
else{
if(newList==null){
newList = list2;
current = newList;
}
else{
current.next = list2;
current = current.next;
}
list2 = list2.next;
}
if(list1!=null){
current.next = list1;
}
if(list2!=null){
current.next = list2;
}
return newList;
}
}
递归做法
public class Solution {
ListNode ret = null;
ListNode current = null;
public ListNode Merge(ListNode list1,ListNode list2) {
if(list1==null) return list2;
if(list2==null) return list1;
ListNode res = null;
if(list1.val<list2.val){
\\先选择出当前节点
res = list1;
res.next = Merge(list1.next, list2);
}
else{
res = list2;
res.next = Merge(list1, list2.next);
}
\\返回的是当前节点和以前节点连接后的结果
return res;
}
}
5. 复杂链表的复制
public class Solution {
public RandomListNode Clone(RandomListNode pHead)
{
//复制数组,连接到一起
if(pHead==null) return pHead;
RandomListNode current = pHead;
while(current!=null){
RandomListNode copyNode = new RandomListNode(current.label);
copyNode.next = current.next;
current.next = copyNode;
current = copyNode.next;
}
// random部位相连
current = pHead;
while(current!=null){
current.next.random = current.random==null?null:current.random.next;
current = current.next.next;
}
RandomListNode head = pHead.next;
current = null;
while(pHead!=null){
current = pHead.next;
// 第一个链表连接
pHead.next = pHead.next.next;
// 第二个链表连接
current.next = current.next==null?null:current.next.next;
// 更新指向
pHead = pHead.next;
}
return head;
}
}
6.两个链表的第一个公共结点
思路:
正常解法是先统计两者的长度并求差,然后让长的先走长度之差;然后两者一起走,直到相等
public class Solution {
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
int count1 = 0;
int count2 = 0;
ListNode current1 = pHead1;
ListNode current2 = pHead2;
while(current1!=null){
current1 = current1.next;
count1++;
}
while(current2!=null){
current2 = current2.next;
count2++;
}
if(count1>=count2){
int diff= count1 - count2;
while(diff>0){
pHead1 = pHead1.next;
diff--;
}
}
else{
int diff = count2 - count1;
while(diff>0){
pHead2 = pHead2.next;
diff--;
}
}
while(pHead1!=pHead2){
pHead1 = pHead1.next;
pHead2 = pHead2.next;
}
return pHead1;
}
}
奇淫技巧
public class Solution {
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
ListNode p1 = pHead1;
ListNode p2 = pHead2;
while(p1!=p2){
p1 = (p1==null?pHead2:p1.next);
p2 = (p2==null?pHead1:p2.next);
}
return p1;
}
}
栈的方法
思路: 如果存在共同节点的话,那么从该节点,两个链表之后的元素都是相同的。
也就是说两个链表从尾部往前到某个点,节点都是一样的。
我们可以用两个栈分别来装这两条链表。一个一个比较出来的值。
找到第一个相同的节点。
import java.util.Stack;
public class Solution {
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
if (pHead1 == null || pHead2 == null) {
return null;
}
Stack<ListNode> stack1 = new Stack<>();
Stack<ListNode> stack2 = new Stack<>();
while (pHead1 != null) {
stack1.push(pHead1);
pHead1 = pHead1.next;
}
while (pHead2 != null) {
stack2.push(pHead2);
pHead2 = pHead2.next;
}
ListNode commonListNode = null;
while (!stack1.isEmpty() && !stack2.isEmpty() && stack1.peek() == stack2.peek() ) {
stack2.pop();
commonListNode = stack1.pop();;
}
return commonListNode;
}
}
7.链表中环的入口结点
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead)
{
if(pHead == null || pHead.next == null)
return null;
ListNode p1 = pHead;
ListNode p2 = pHead;
while(p1!=null&&p2.next!=null){
p1 = p1.next;
p2 = p2.next.next;
if(p1==p2){
p2 = pHead;
while(p1!=null&&p2!=null){
if(p1==p2) return p1;
p1 = p1.next;
p2 = p2.next;
}
}
}
return p1;
}
}
8. 删除链表中的重复结点
public class Solution {
public ListNode deleteDuplication(ListNode pHead)
{
if(pHead==null||pHead.next==null) return pHead;
// 重点是这里,头结点可能被删除,所以我们得新建一个结点来连接原来的头结点
ListNode first = new ListNode(-1);
first.next = pHead;
ListNode current = first;
ListNode last = pHead;
// 因为要比较last和last.next,所以条件为两个都不为null
while(last!=null&&last.next!=null){
if(last.val==last.next.val){
while(last.next!=null&&last.val==last.next.val){
last = last.next;
}
// 连接
current.next = last.next;
// 更新
last = last.next;
}
else{
last = last.next;
current = current.next;
}
}
return first.next;
}
}