链表题目总结

链表题目总结

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;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值