代码随想录刷题——day4

57 阅读3分钟

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

  /**
     * Definition for singly-linked list.
     * public class ListNode {
     *     int val;
     *     ListNode next;
     *     ListNode() {}
     *     ListNode(int val) { this.val = val; }
     *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
     * }
     */
    class Solution {
        public ListNode swapPairs(ListNode head) {
            //如果链表为空 或者链表只存在头结点 就直接返回
            if(head==null || head.next==null){
                return head;
            }
            ListNode fakeHead=new ListNode();
            fakeHead.next=head;
            ListNode prePreNode=new ListNode();
            prePreNode=fakeHead;
            //这个循环判断语句是为了判断偶数结点链表两两交换到底了 或者  奇数链表的情况
            while(prePreNode.next!=null && prePreNode.next.next!=null){
                //始终用prePreNode记录要被交换的两个节点的前一个节点。
                //swapedFormerNode 要被两两交换的两个节点的第一个节点 
                //swapedLatterNode 要被两两交换的两个节点的第二个节点
                ListNode swapedFormerNode= prePreNode.next;
                ListNode swapedLatterNode=swapedFormerNode.next;
                //两两交换操作
                prePreNode.next=swapedLatterNode;
                swapedFormerNode.next=swapedLatterNode.next;
                swapedLatterNode.next=swapedFormerNode;
                //prePreNode更新,继续指向下一对两两交换的节点的上一个结点
                prePreNode=prePreNode.next.next;
    
            }
            return fakeHead.next;
        }
    }

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

具体代码
方法一:获取链表长度

思路:

先通过遍历获取整个链表的长度,然后将length-n作为遍历的基准条件,以此来遍历得到要被删除的节点的上一个结点。


    /**
     * Definition for singly-linked list.
     * public class ListNode {
     *     int val;
     *     ListNode next;
     *     ListNode() {}
     *     ListNode(int val) { this.val = val; }
     *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
     * }
     */
    class Solution {
        public ListNode removeNthFromEnd(ListNode head, int n) {
            //统计链表长度
            ListNode fakeHead=new ListNode();
            fakeHead.next=head;
            int len=0;
            ListNode temp=fakeHead;
            while(temp.next!=null){
                temp=temp.next;
                len++;
            }
            //找到要被删除结点的上一个结点
            ListNode pre = fakeHead;
            int count=0;
            while(count!=len-n){
                pre=pre.next;
                count++;
            }
            //删除操作
            pre.next=pre.next.next;
            return fakeHead.next;
        }
    }
方法二:快慢指针

单链表中的所有删除操作,一定一定是要找到被删除结点的上一个结点。

(在使用虚拟头结点的基础上)通过模拟,可以发现,如果让快指针先走n步,而后快慢节点再同时出发,当快结点到最后null时,此时慢节点正好指向要被删除的倒数第n个结点。

但是为了让slow慢结点指向倒数第n个结点的上一个结点,fast结点就要多走一步,即n+1步。

/**
     * Definition for singly-linked list.
     * public class ListNode {
     *     int val;
     *     ListNode next;
     *     ListNode() {}
     *     ListNode(int val) { this.val = val; }
     *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
     * }
     */
    class Solution {
        public ListNode removeNthFromEnd(ListNode head, int n) {
            ListNode fakeNode=new ListNode();
            fakeNode.next=head;
            //初始时,slow和fast指针都指向虚拟头结点
            ListNode slow=fakeNode;
            ListNode fast=fakeNode;
            //将快指针往前移动n+1个结点
            for(int i=0;i<n+1;i++){
                fast=fast.next;
            }
            while(fast!=null){
                fast=fast.next;
                slow=slow.next;
            }
            slow.next=slow.next.next;
            return fakeNode.next;
    
        }
    }

142.环形链表II

具体代码

暴力解法

实在想不出别的,目前只想出来暴力解法。极其之暴力。使用了很多空间以及时间。(但是leetcode能通过)

至于更加优雅的算法,参考carl哥,但是目前个人尚不能理解。故不贴

    /**
     * Definition for singly-linked list.
     * class ListNode {
     *     int val;
     *     ListNode next;
     *     ListNode(int x) {
     *         val = x;
     *         next = null;
     *     }
     * }
     */
    public class Solution {
        public ListNode detectCycle(ListNode head) {
            //暴力解法
            //map用于记录哪些节点已经访问过了
            Map<ListNode,Integer> map=new HashMap<>();
            if(head==null || head.next==null){
                return null;
            }
            //通过上面if语句的排除 可以知道目前的链表最少最少也有两个结点
            ListNode current= head;
            ListNode temp=current;
            while(true){
                map.put(temp,1); //把当前节点放入map中 代表已经遍历过了
                //temp指向下一个
                temp=temp.next;
                //无环
                if(temp.next==null){
                    return null;
                }
                //只要这个结点已经被遍历过了,那么它肯定是环的起点!!!  
                if(map.containsKey(temp)){
                    return temp;
                }
    
            }
    
        }
    
    }