代码随想录算法训练营第四天 | 24. 两两交换链表中的节点,19.删除链表的倒数第N个节点,面试题 02.07. 链表相交,142.环形链表II

24. 两两交换链表中的节点

24.两两交换链表中的节点

思路:

  1. 头节点要更改,加入虚拟头节点
  2. 在变换中,三个节点参与变化,第一个节点位置不变,指向第三个节点,第三个节点指向第二个节点,第二个节点指向原第三个节点的下个节点,~~交换完成后三个节点整体右移,~~第一个节点变为第二个节点所在位置(只需要移动第一个节点即可,在循环体前面得到下两个节点),后面两个节点为新的节点
  3. 循环结束条件(不太清楚):第一个节点的下一个节点和下下个节点为空(fristNode.next!=null && fristNode.next.next!=null)

两两交换链表中的节点-三节点参与

  • Java代码

    • 三个节点参与
    class Solution {
        public ListNode swapPairs(ListNode head) {
            if (head==null || head.next==null) return head;
            ListNode dummy = new ListNode();
            dummy.next=head;
    //            ListNode cur=dummy, fristNode=head, secondNode=head.next;
            ListNode cur=dummy, fristNode, secondNode;
    //            while (secondNode!=null && secondNode.next!=null && secondNode.next.next!=null) {
            while (cur.next!=null && cur.next.next!=null) {
                fristNode = cur.next;
                secondNode = cur.next.next;
                ListNode temp = secondNode.next;
                cur.next=secondNode;
                secondNode.next=fristNode;
                fristNode.next=temp;            // 要管单次循环体中的完整交换,不然无法处理循环结束时的情况
                cur=fristNode;
                /*fristNode=temp;
                secondNode=temp.next;*/         // 只需要移动第一个节点即可(不然可能会计算空节点的下一个节点),在前面得到相邻的下两个节点
            }
            return dummy.next;
        }
    }
    

    时间复杂度:O(n)
    空间复杂度:O(1)

    • 完整代码
    package topic2ListNode;
    
    /*24. 两两交换链表中的节点
    
        给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
    
        示例 1:
    
        输入:head = [1,2,3,4]
        输出:[2,1,4,3]
        链接:https://leetcode.cn/problems/swap-nodes-in-pairs/*/
    public class topic4_24 {
        public static void main(String[] args) {
            Solution solution = new topic4_24().new Solution();
            int[] arr = {1,2,3,4};
            ListNode head = new ListNode(arr);
            head.print();
            ListNode newHead = solution.swapPairs(head);
            newHead.print();
        }
        class Solution {
            public ListNode swapPairs(ListNode head) {
                if (head==null || head.next==null) return head;
                ListNode dummy = new ListNode();
                dummy.next=head;
    //            ListNode cur=dummy, fristNode=head, secondNode=head.next;
                ListNode cur=dummy, fristNode, secondNode;
    //            while (secondNode!=null && secondNode.next!=null && secondNode.next.next!=null) {
                while (cur.next!=null && cur.next.next!=null) {
                    fristNode = cur.next;
                    secondNode = cur.next.next;
                    ListNode temp = secondNode.next;
                    cur.next=secondNode;
                    secondNode.next=fristNode;
                    fristNode.next=temp;            // 要管单次循环体中的完整交换,不然无法处理循环结束时的情况
                    cur=fristNode;
                    /*fristNode=temp;
                    secondNode=temp.next;*/         // 只需要移动第一个节点即可(不然可能会计算空节点的下一个节点),在前面得到相邻的下两个节点
                }
                return dummy.next;
            }
        }
    }
    

19.删除链表的倒数第N个节点

19.删除链表的倒数第N个节点

思路:

  1. 找到要删除节点(cur)的前一个节点(pre),前一个节点指向下下个节点(pre.next=cur.next)
  2. 循环终止条件:前一个节点的下 n+1 个节点为空(找到要删除节点的前一个节点,要删除节点的下n个节点为空)
    额外的补充:
  3. 添加虚拟头节点(因为可以对头节点进行操作)
  • Java代码

    • 双指针法
    class Solution {
        public ListNode removeNthFromEnd(ListNode head, int n) {
            ListNode dummy = new ListNode();
            dummy.next = head;
            ListNode cur = dummy, pre = dummy;
            while (n-- >= 0){
                cur=cur.next;
            }
            while (cur!=null) {
                cur=cur.next;
                pre=pre.next;
            }
            pre.next=pre.next.next;
            return dummy.next;
        }
    }
    

    时间复杂度:O(n) 实际是O(2n-index)
    空间复杂度:O(1)

    • 完整代码
    package topic2ListNode;
    
    /*19. 删除链表的倒数第 N 个结点
    
        给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
    
        示例 1:
    
        输入:head = [1,2,3,4,5], n = 2
        输出:[1,2,3,5]
    
        链接:https://leetcode.cn/problems/remove-nth-node-from-end-of-list/*/
    
    public class topic5_19 {
        public static void main(String[] args) {
            Solution solution = new topic5_19().new Solution();
            int[] arr = {1, 2, 3, 4, 5};
            int n = 2;
            ListNode head = new ListNode(arr);
            head.print();
            System.out.println("要删除倒数第" + n + "个节点");
            ListNode newHead = solution.removeNthFromEnd(head, n);
            newHead.print();
        }
    
        class Solution {
            public ListNode removeNthFromEnd(ListNode head, int n) {
                ListNode dummy = new ListNode();
                dummy.next = head;
                ListNode cur = dummy, pre = dummy;
                while (n-- >= 0) {
                    cur = cur.next;
                }
                while (cur != null) {
                    cur = cur.next;
                    pre = pre.next;
                }
                pre.next = pre.next.next;
                return dummy.next;
            }
        }
    }
    
    

面试题 02.07. 链表相交

面试题 02.07.链表相交

思路:

  1. 定义两个从头开始的节点(curA和curB),分别沿着各自的链表进行遍历,并进行判断是否相同
  2. 当两个运动的节点到达各自的终点后(不同时为null),分别从对方的起点开始运动
  3. 循环终止条件:两个运动节点相同(同时为空或者是达到相交节点,curA!=curB)
    原理:
    A链表长度为n,B链表长度为m,curA节点运动长度为 n+m,curB节点运动长度为 m+n
  • Java代码

    • 双指针
    public class Solution {
        public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
            ListNode curA=headA, curB=headB;
            while (curA!=curB) {
                curA = curA!=null ? curA.next : headB;
                curB = curB!=null ? curB.next : headA;
            }
            return curA;
        }
    }
    

    时间复杂度:O(n) 实际是O(2(m+n))
    空间复杂度:O(1)

    • 完整代码
    package topic2ListNode;
    
    /*面试题 02.07. 链表相交
    
        给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
    
        图示两个链表在节点 c1 开始相交:
    
    
    
        题目数据 保证 整个链式结构中不存在环。
    
        注意,函数返回结果后,链表必须 保持其原始结构 。
    
        来源:力扣(LeetCode)
        链接:https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci
        著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
    
        示例 1:
    
        输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
        输出:Intersected at '8'
        解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。
        从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。
        在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。*/
    
    public class topic6_0207 {
        public static void main(String[] args) {
            Solution solution = new topic6_0207().new Solution();
            int[] arrA = {4,1};
            int[] arrB = {5,0};
            int[] arrIntersect = {8,4,5};
            ListNode headA = new ListNode(arrA);
            ListNode headB = new ListNode(arrB);
            ListNode headIntersect = new ListNode(arrIntersect);
            headA.addListNode(headIntersect);
            headB.addListNode(headIntersect);
            headA.print();
            headB.print();
            ListNode intersectNode = solution.getIntersectionNode(headA, headB);
            intersectNode.print();
        }
        public class Solution {
            public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
                ListNode curA=headA, curB=headB;
                while (curA!=curB) {
                    curA = curA!=null ? curA.next : headB;
                    curB = curB!=null ? curB.next : headA;
                }
                return curA;
            }
        }
    }
    
    

142.环形链表II

142.环形链表II

思路:

  1. 使用快慢指针找到链表是否相交(快指针每次移动2个长度,慢指针每次移动1个长度)
  2. 若未找到(快指针为null),循环结束条件:快指针为空,并且快指针的下个节点为空(fast!=null && fast.next!=null)
  3. 找到后根据移动关系(x=y+(n-1)(y+z)),重新制定两个指定,相交处即是链表的环入口
    142环形链表II

具体细节过程细节

  • Java代码

    • 双指针
    public class Solution {
        public ListNode detectCycle(ListNode head) {
            if (head==null) {return null;}
            ListNode dummy = new ListNode();
            dummy.next = head;
            ListNode fast=dummy, slow=dummy;
            while (fast!=null && fast.next!=null) {
                slow=slow.next;
                fast=fast.next.next;
                if (slow==fast) {
                    ListNode index1 = fast;
                    ListNode index2 = dummy;
                    while (index1!=index2) {
                        index1=index1.next;
                        index2=index2.next;
                    }
                    return index1;
                }
            }
            return null;
        }
    }
    

    时间复杂度:O(n),快慢指针相遇前,指针走的次数小于链表长度,快慢指针相遇后,两个index指针走的次数也小于链表长度,总体为走的次数小于 2n
    空间复杂度:O(1)

    • 完整代码
    package topic2ListNode;
    
    /*142. 环形链表 II
    
        给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
    
        如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
    
        不允许修改 链表。
    
        来源:力扣(LeetCode)
        链接:https://leetcode.cn/problems/linked-list-cycle-ii
        著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
    
        示例 1:
    
        输入:head = [3,2,0,-4], pos = 1
        输出:返回索引为 1 的链表节点
        解释:链表中有一个环,其尾部连接到第二个节点。*/
    
    public class topic7_142 {
        public static void main(String[] args) {
            Solution solution = new topic7_142().new Solution();
            int[] arr = {3,2,0,-4};
            int index = 1;
            ListNode head = new ListNode(arr);
            head.print();
            System.out.println("index: "+index);
            head.createCircle(1);
            ListNode cycleNode = solution.detectCycle(head);
            System.out.println(cycleNode.val);
        }
    
        public class Solution {
            public ListNode detectCycle(ListNode head) {
                if (head==null) {return null;}
                ListNode dummy = new ListNode();
                dummy.next = head;
                ListNode fast=dummy, slow=dummy;
                while (fast!=null && fast.next!=null) {
                    slow=slow.next;
                    fast=fast.next.next;
                    if (slow==fast) {
                        ListNode index1 = fast;
                        ListNode index2 = dummy;
                        while (index1!=index2) {
                            index1=index1.next;
                            index2=index2.next;
                        }
                        return index1;
                    }
                }
                return null;
            }
        }
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值