一刷剑指Offer:链表专题

剑指Offer_6:从尾到头打印链表

题目:输入一个链表,按链表从尾到头的顺序返回一个ArrayList。

思路1:使用栈,利用栈的先进后出的特点,将链表的节点压入栈中,然后再弹出。

class ListNode {
    int val;
    ListNode next = null;
    ListNode(int val) {
        this.val = val;
    }
}

public class Solution {
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        Stack<Integer> stack = new Stack<>();
        ArrayList<Integer> list = new ArrayList<>();
        while(listNode!=null){
           stack.push(listNode.val);
           listNode = listNode.next;
        }
       //将栈顶的元素弹出
        while (!stack.isEmpty()){
           list.add(stack.pop()) ;
        }
        return list;
    }
}

思路2:使用递归来实现。

public class Solution {
     public static ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        ArrayList<Integer> list = new ArrayList<>();
        if(listNode==null){
            return list;
        }
        return dp(list,listNode);
    }

    private static ArrayList<Integer> dp(ArrayList<Integer> list, ListNode listNode) {
        //递归的条件
        if(listNode.next!=null){
            list = dp(list,listNode.next);
        }
        //递归条件不满足时要做的事
        list.add(listNode.val);
        return list;
    }
}

剑指offer_6(LeetCode):从尾到头打印链表

题目:输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)

class Solution {
    public int[] reversePrint(ListNode head) {
       Stack<Integer> stack = new Stack<>();
       ListNode temp = head;
      
       while(temp!=null) {
           stack.push(temp.val);
           temp = temp.next;
       }
        int[] arr = new int[stack.size()];
       for(int i=0;i<arr.length;i++){
           arr[i] = stack.pop();
       }
       return arr;
    }
}

剑指Offer_53:链表中环的入口节点

题目:给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

public class Solution {
    public ListNode EntryNodeOfLoop(ListNode pHead) {
        /**
         * 1、先判断链表是否成环
         */
        if(pHead==null || pHead.next==null){
            return null;
        }

        ListNode slow = pHead;
        ListNode fast = pHead;
        boolean flag = false;
        while (fast!=null && fast.next!=null){
            slow = slow.next;
            fast = fast.next.next;
            if(fast == slow){
                flag = true;
                break;
            }
        }
        if(flag){
            /**
             * 2、计算环的长度,让快指针多走一圈就可以得到环的长度,相遇就可以
             */
            int length = 1;
            fast = fast.next;
            while (slow!=fast){
                fast = fast.next;
                length++;
            }

            /**
             * 3、找到环的入口节点:
             *      让快慢指针都从头开始走,因为快指针比慢指针多走环的长度个节点
             *      让快指针先走环的长度个节点,然后两个指针走的节点就一样了,这样快慢节点肯定会相遇
             */
            fast = slow = pHead;
            for(int i=0;i<length;i++){
                fast = fast.next;
            }
            while (slow!=fast){
                slow = slow.next;
                fast = fast.next;
            }
            return fast;
        }else{
            return null;
        }
    }
}

剑指Offer_18:删除链表中重复的节点

题目:在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

public class Solution {
    public ListNode deleteDuplication(ListNode pHead) {
        ListNode dummuy = new ListNode(0);
        dummuy.next = pHead;
        ListNode cur = dummuy;
        while (cur.next!=null && cur.next.next!=null){
            if(cur.next.val==cur.next.next.val){
                ListNode tmp = cur.next;
                while (tmp!=null && tmp.next!=null && tmp.val==tmp.next.val){
                    tmp = tmp.next;
                }
                cur.next = tmp.next;
            }else{
                cur = cur.next;
            }
        }
        return dummuy.next;
    }
}

剑指Offer_22:链表中倒数第K个节点

题目:输入一个链表,输出该链表中倒数第k个结点。
在这里插入图片描述

public class Solution {
    public ListNode FindKthToTail(ListNode head,int k) {
        /**
         * 1、使用快慢指针:让两个指针fast和slow都指向头指针
         * 2、让fast指针先走k个节点
         * 3、然后让fast和slow同时走
         * 4、当fast走到链表结尾时,slow指向的就是倒数第k个节点
         */
        ListNode fast = head;
        ListNode slow = head;
        for(int i=0;i<k;i++){
            if(fast==null){
                return null;
            }
            fast = fast.next;
        }
        while (fast!=null){
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
    }
}

剑指Offer_24:反转链表

题目:输入一个链表,反转链表后,输出新链表的表头。

public class Solution {
    public ListNode ReverseList(ListNode head) {
        /**
         * 进性边界条件判断:
         * 1、如果节点为null,直接返回该节点
         * 2、如果只有一个节点,直接返回该节点
         */
        if(head==null || head.next==null){
            return head;
        }

        /**
         * 1、定义一个临时节点cur一直指向cur的下一个节点,保证链表不会断掉
         * 2、定义一个辅助节点遍历这个链表,刚开始指向head
         * 3、让cur.next指向pre,然后让pre指向cur
         * 4、让cur和tmp同时后移
         */
        ListNode pre = null;
        ListNode tmp = null;
        ListNode cur = head;
        while (cur!=null){
            tmp = cur.next;//tmp后移
            cur.next = pre;
            pre = cur;
            cur = tmp;//cur后移
        }
        return pre;
    }
}

剑指Offer_25:合并两个排序的链表

题目:输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

扫描二维码关注公众号,回复: 11211089 查看本文章
public class Solution {
    public ListNode Merge(ListNode list1,ListNode list2) {
        /**
         * 1、定义一个伪节点dum,连接合并后的新链表
         * 2、因为头结点不能动,定义一个辅助指针cur,遍历合并后的新链表
         * 3、遍历两个链表,比较节点的值,将较小的节点加到新链表节点后面
         */
        ListNode dum = new ListNode(0);
        ListNode cur = dum;
        while (list1!=null && list2!=null){
            if(list1.val<=list2.val){
                cur.next = list1;
                list1 = list1.next;
            }else{
                cur.next = list2;
                list2 = list2.next;
            }
            cur = cur.next;
        }
        /**
         * 如果链表1或2中有剩余节点就添加到新链表的结尾
         */
        if(list1!=null){
            cur.next = list1;
        }else if(list2!=null){
            cur.next = list2;
        }
        return dum.next;
    }
}

剑指Offer_36:二叉搜索树与双向链表

题目:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。

public class Solution {
    /**
     * 中序遍历的顺序就是递增的,利用这个性质
     */
    public TreeNode Convert(TreeNode pRootOfTree) {
        if(pRootOfTree==null){
            return null;
        }

        ArrayList<TreeNode> list = new ArrayList<>();
        inOrder(pRootOfTree,list);
        /**
         * 将集合中的节点变成双向链表:
         * 1、第一个节点的左子节点为null
         * 2、定义一个辅助指针cur,遍历节点
         * 3、遍历每个节点,将其左子节点设为前驱节点,后一个节点设为后继节点
         * 3、让cur后移
         */
        TreeNode head = list.get(0);
        head.left = null;
        TreeNode cur = head;
        for(int i=1;i<list.size();i++){
            cur.right = list.get(i);
            list.get(i).left = cur;
            cur = cur.right;
        }
        return head;
    }

    /**
     * 这个方法的作用就是中序遍历,并将遍历的结果存入list集合中
     */
    private void inOrder(TreeNode pRootOfTree, ArrayList<TreeNode> list) {
        //递归的边界条件
        if(pRootOfTree == null){
            return;
        }
        inOrder(pRootOfTree.left,list);
        list.add(pRootOfTree);
        inOrder(pRootOfTree.right,list);
    }
}

剑指Offer_52:两个链表的第一个公共节点

题目:输入两个链表,找出它们的第一个公共节点。

本题有两种解题方法:

思路1:两个指针,一个指针指向A,一个指针指向B,让他们遍历两个链表,每遍历一个节点就比较一次,判断是不是相等,相等就退出循环,如果A先走到链表的尾部,就从该链表的头开始走,如果B走到了链表的尾部,也从该链表的头开始走,最终两个指针一定会相遇在第一个公共节点。(不断减小两者的节点差)

public class Solution {
    public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
        ListNode cur1 = pHead1;
        ListNode cur2 = pHead2;
        while (cur1!=cur2){
            if(cur1==null){
                cur1 = pHead1;
            }else{
                cur1 = cur1.next;
            }

            if(cur2==null){
                cur2 = pHead2;
            }else{
                cur2 = cur2.next;
            }
        }
        return cur1;
    }
}

思路2:两个指针,一个指针指向A,一个指针指向B,让他们遍历两个链表,每遍历一个节点就比较一次,判断是不是相等,相等就退出循环,如果A先走到链表的尾部,就从B链表的头开始走,如果B走到了链表的尾部,从A链表的头开始走,最终两个指针一定会相遇在第一个公共节点。
在这里插入图片描述

public class Solution {
    public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
        ListNode cur1 = pHead1;
        ListNode cur2 = pHead2;
        while (cur1!=cur2){
            if(cur1==null){
                cur1 = pHead2;
            }else{
                cur1 = cur1.next;
            }

            if(cur2==null){
                cur2 = pHead1;
            }else{
                cur2 = cur2.next;
            }
        }
        return cur1;
    }
}
原创文章 723 获赞 153 访问量 18万+

猜你喜欢

转载自blog.csdn.net/qq_42764468/article/details/105633082