剑指offer——链表

题目代号: 剑指 Offer 06. 从尾到头打印链表

题目描述:

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

测试用例:

输入:head = [1,3,2]
输出:[2,3,1]

我的分析:

放在栈里面,真的是极好的,因为这样就相当于倒序了

代码:

public class offer6 {
    public static void main(String[] args) {

    }

    public int[] reversePrint(ListNode head) {
        Stack<ListNode> stack = new Stack<ListNode>();
        ListNode temp = head;
        while (temp != null){
            stack.push(temp);
            temp = temp.next;
        }
        int size = stack.size();//必须要在这里提出这个长度,为啥呢,链表长度会变的,
        // 你要是放在里面,它长度一直变化,会缩短的
        int[] res = new int[size];
        for (int i = 0;i < size;i++){
            res[i] = stack.pop().val;
        }
        return res;
    }
}

题目代号: 剑指 Offer 22. 链表中倒数第k个节点

题目描述:

输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。

例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6。这个链表的倒数第 3 个节点是值为 4 的节点。

测试用例:

给定一个链表: 1->2->3->4->5, 和 k = 2.

返回链表 4->5.

我的分析:

搞双指针都指向头部

前面的指针先向前走k步,然后他俩就差k步了

然后他俩一起走,前面的到终点,后面的指向的位置就是所求位置

而且链表这东西,只要头节点定了,那后面的就一串都连起来了(就像链子一样)

代码:

public ListNode getKthFromEnd(ListNode head, int k) {
        ListNode former = head,later = head;
        for(int i = 0;i < k;i++){
            former = former.next;
        }
        while (former != null){
            former = former.next;
            later = later.next;
        }
        return later;
    }

题目代号: 剑指 Offer 24. 反转链表

题目描述:

定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。

测试用例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

我的分析:
在这里插入图片描述
其实就是一前一后,变成一后一前

代码:

public ListNode reverseList(ListNode head) {
        ListNode qian = head,hou = null;
        while (qian != null){
            ListNode next = qian.next;//把前面下一步移动的点先拿出来(暂存一下)
            qian.next = hou;//指向
            hou = qian;//指针赋值替换
            qian = next;

        }
        return hou;
    }

题目代号: 剑指 Offer 25. 合并两个排序的链表

题目描述:

输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。

测试用例:

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

我的分析:

新建一个指针的头节点是0
然后各自遍历,把小的往上挂

挂完后肯定有一串是富余的,那就把这串挂到结尾

代码:

public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode zong = new ListNode(0),temp = zong;
        while (l1 != null && l2 != null){
            if(l1.val <= l2.val){
                temp.next = l1;
                l1 = l1.next;
            }else {
                temp.next = l2;
                l2 = l2.next;
            }
            temp = temp.next;
        }
        temp.next = l1 != null? l1:l2;
        return zong.next;
    }

题目代号: 剑指 Offer 35. 复杂链表的复制

题目描述:

请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。

测试用例:

在这里插入图片描述
输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]

我的分析:

建立一个hashmap作为中转站,把节点先放进去

然后就根据键找只值,然后连接起来就好了

代码:

 public Node copyRandomList(Node head) {
        if(head == null) return null;
        Node temp = head;//这个指针是一直动的指针
        Map<Node,Node> map = new HashMap<>();
        while (temp != null){
            map.put(temp, new Node(temp.val));
            temp = temp.next;

        }
        Node cur = head;//现在已经放进map里面
        //在map里面的新节点连接起来就行了
        while (cur != null){
            map.get(cur).next = map.get(cur.next);
            map.get(cur).random = map.get(cur.random);
            cur = cur.next;
        }
        return map.get(head);

    }

题目代号: 剑指 Offer 52. 两个链表的第一个公共节点

题目描述:

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

如下面的两个链表:
在这里插入图片描述

在节点 c1 开始相交。

测试用例:

示例 1:

在这里插入图片描述

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。

我的分析:

两个思路:
思路一:创建两个栈,都压入,然后同时弹出,看是不是相等

思路二:指针1从链表A开始,然后遍历链表B
指针2从链表B开始,然后遍历链表A

代码:

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if(headA == null || headB == null) return null;
        ListNode l1 = headA;
        ListNode l2 = headB;
        Stack<ListNode> stack1 = new Stack<ListNode>();
        Stack<ListNode> stack2 = new Stack<ListNode>();
        while (l1 != null){
            stack1.push(l1);
            l1 = l1.next;
        }
        while (l2 != null){
            stack2.push(l2);
            l2 = l2.next;
        }//都压入栈
        
        if(stack1.peek() == stack2.peek()){
            ListNode jieguo = null;
            while (!stack1.empty() && !stack2.empty() && stack1.peek() == stack2.peek()){
                stack1.pop();
                jieguo = stack2.pop();
            }//当不进入这个栈的时候说明已经不相等了
            return jieguo;
        }

        return null;
        
            
    }
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if (headA == null || headB == null) {
            return null;
        }

        ListNode head1 = headA;
        ListNode head2 = headB;

        while (head1 != head2) {
            if (head1 != null) {
                head1 = head1.next;
            } else {
                head1 = headB;
            }

            if (head2 != null) {
                head2 = head2.next;
            } else {
                head2 = headA;
            }
        }
        return head1;
            
    }

题目代号: 142. 环形链表 II

题目描述:

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意,pos 仅仅是用于标识环的情况,并不会作为参数传递到函数中。

测试用例:

在这里插入图片描述

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。

我的分析:

两个思路:

思路一:放进HashSet,看有重复的时候,那就是它了

思路二:快指针走两步,慢指针走一步,肯定能相遇的,相遇后,让另一个指针从头开始走,相遇点就是入口点

数学证明一下:

我们使用两个指针,fast 与 slow。它们起始都位于链表的头部。随后,slow 指针每次向后移动一个位置,而 fast 指针向后移动两个位置。如果链表中存在环,则 fast 指针最终将再次与slow 指针在环中相遇。

如下图所示,设链表中环外部分的长度为 a。slow 指针进入环后,又走了 b 的距离与fast 相遇。此时,fast 指针已经走完了环的 n 圈,因此它走过的总距离为 a+n(b+c)+b=a+(n+1)b+nc
在这里插入图片描述
根据题意,任意时刻,fast 指针走过的距离都为 slow 指针的 2 倍。因此,我们有

a+(n+1)b+nc=2(a+b) ⟹ a=c+(n−1)(b+c)

有了 a=c+(n-1)(b+c)a=c+(n−1)(b+c) 的等量关系,我们会发现:从相遇点到入环点的距离加上 n-1 圈的环长,恰好等于从链表头部到入环点的距离。

因此,当发现 slow 与 fast 相遇时,我们再额外使用一个指针 ptr。起始,它指向链表头部;随后,它和 slow 每次向后移动一个位置。最终,它们会在入环点相遇。

代码:

//思路一
public class Solution {
    public ListNode detectCycle(ListNode head) {
        HashSet<ListNode> set = new HashSet<>();
        while(head != null){
            set.add(head);
            head = head.next;
            if(set.contains(head)){
                return head;
            }
        }
        return null;    
    }
}
//思路二
public ListNode detectCycle(ListNode head) {
	ListNode slow = head,fast = head;
    while (true){
    	if(fast == null || fast.next == null){//一条直路的情况,没有环路
        	return null;
        }
        fast = fast.next.next;
        slow = slow.next;//既然有环路,那就一直直行

        if(slow == fast){
        	ListNode pre = head;
            while (pre != slow){
            	pre = pre.next;
                slow = slow.next;
            }
            	return slow;
        }
   }
}

题目代号: 82. 删除排序链表中的重复元素 II

题目描述:

存在一个按升序排列的链表,给你这个链表的头节点 head ,请你删除链表中所有存在数字重复情况的节点,只保留原始链表中 没有重复出现 的数字。

返回同样按升序排列的结果链表。

测试用例:

在这里插入图片描述
输入:head = [1,2,3,3,4,4,5]
输出:[1,2,5]

我的分析:

走一步看看后两个节点是否为空,是否相等,相等了就用一个新节点把相等的都搞没

代码:

class Solution {
    public ListNode deleteDuplicates(ListNode head) {

        ListNode dummyHead = new ListNode(0,head);//在头节点前面加一个哑节点
        ListNode temp1 = dummyHead;//让temp1指针从哑节点开始
        if(temp1.next == null||temp1.next.next == null){//第一个节点或者第二个节点是空
            return temp1.next;//直接返回头节点
        }
        
		//这道题必须要做到走一步,就要看后面两个节点是否相等
        while (temp1.next != null && temp1.next.next != null){
            if(temp1.next.val == temp1.next.next.val){//当后两个节点相等的时候
                ListNode temp2 = temp1.next;//让指针temp2去动吧
                while ( temp2 != null && temp2.next != null &&temp2.val == temp2.next.val){
                    temp2 = temp2.next;//temgp2的下一个节点就是不相同的节点
                }
                temp1.next = temp2.next;//因此让temp1指向temp2的下一个节点
            }else{
                temp1 = temp1.next;
            }

        }
        return dummyHead.next;//返回的是哑节点的下一个节点

    }
}

题目代号: 剑指 Offer 18. 删除链表的节点

题目描述:

给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。

返回删除后的链表的头节点。

测试用例:

输入: head = [4,5,1,9], val = 1
输出: [4,5,9]
解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.

我的分析:

就一个快指针,一个慢指针,一步一步向前挪动

最后让慢指针指向快指针的下一位

代码:

public ListNode deleteNode(ListNode head, int val) {
        if(head.val == val) return head.next;
        ListNode slow = head,fast = head.next;
        while (fast != null && fast.val != val){
            slow = fast;
            fast = fast.next;
        }
        if(fast != null) slow.next = fast.next;
        return head;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值