Leetcode链表总结

    由于最近开始面临保研找实习,所以打算刷波leetcode,之前一直想做这件事,巩固一下自己的基础,但总是被各种事情耽搁,由此写下这篇博客作为督促。在这期间偶然间看到同学的博客,他也打算刷leetcode,但刚做了一题就拿到了滴滴的offer,而且那一题跟我做的第一道题一样,让人感叹的巧合。希望我也能像他一样得到满意的结果。

    本篇文章不会包含代码的讲解,只是做题目的一点思路心得,相关答案可以访问leetcode

2. Add Two Numbers

比较简单的链表相加问题,除了要考虑到链表不一样长的情况,还有最高位进位为1。思考到细节。

另外,在solution中看到了为链表加空表头的方式,解决了插入判断一致性问题,也是一个比较基础的操作。

19. Remove Nth Node From End of List

删除倒数第n个节点,双指针问题,第一个指针走n步,第二个指针与第一个指针一起移动,需考虑删除节点为头节点的情况。也可通过添加一空头,消除头节点的特殊判断。

24. Swap Nodes in Pairs

交换相邻节点,添加空头消除头节点特殊情况,考虑链表长度为奇数的特殊情况。

82. Remove Duplicates from Sorted List II

有序表删除重复元素,按值找出需删除的一段链表,修改指针,添加空头消除头节点特殊判断。


92. Reverse Linked List II

在206题反转链表的基础上,在链表上加入某范围的反转,反转链表使用三个指针,从头到尾依次把后一块移动到前一块。由于反转的是链表的部分,头部有可能改变也可能不改变,因此加入空头消除特殊性,small和big指针分别记录需反转链表的前一块和后一块的地址,之后使用206题方法对链表进行反转即可。

看了讨论区,发现也不用计算链表末尾值,根据n-m即可知道移动块的次数,少了一次需反转链表的遍历。


109. Convert Sorted List to Binary Search Tree

将有序链表转换为平衡BST树,采用递归的方式,链表中部元素作为树根,左右子树依次对两端链表进行同种操作,寻找中部元素使用两个指针,一个一次走一步,另一个一次走两步,即可找到中部元素,代码如下

public TreeNode sortedListToBST(ListNode head) {
        if(head==null) return null;
        ListNode fast=head;
        ListNode slow=head;
        ListNode pre=head;
        while(fast!=null&&fast.next!=null) {  //快指针走到尾部时
            pre=slow;
            slow=slow.next;
            fast=fast.next.next;
        }
        pre.next=null; //将链表断开
        TreeNode treehead = new TreeNode(slow.val); //new一根节点
        if(head==slow) return treehead;  //只剩一个节点不进行递归
        else {
            treehead.left=sortedListToBST(head);
            treehead.right=sortedListToBST(slow.next);
        }
        return treehead;
    }

看到讨论区中有不将链表断开,另写一个函数传入tail,将null判断改为是否等于tail判断,少了一个指针。

138. Copy List with Random Pointer

random指针链表深拷贝,一直在考虑如何找到重复节点,其实也是一个索引问题,使用hashmap,被拷贝链表作为key,拷贝节点为value,从头开始一一连接指针即可。

public RandomListNode copyRandomList(RandomListNode head) {
        Map<RandomListNode,RandomListNode> map = new HashMap<>();
        //第一次遍历做映射
        RandomListNode tmp = head;
        while(tmp!=null) {
            map.put(tmp,new RandomListNode(tmp.label));
            tmp=tmp.next;
        }
        //第二次遍历做连接
        tmp=head;
        while(tmp!=null) {
            map.get(tmp).next=map.get(tmp.next);
            map.get(tmp).random=map.get(tmp.random);
            tmp=tmp.next;
        }
        
        return map.get(head);
    }

142. Linked List Cycle II

在141判断是否有环形链表的基础上,返回入环的第一个节点。在不使用另外存储空间的情况下。判断环形链表使用双指针,一个一次走两步,另一个一次走一步,如果链表中有环,那么指针会相遇。返回入环的第一个节点需要数学推导,即当两指针相遇后,将一个指针退回head,之后各自走一步,再次相遇时便是入环的第一个节点。

public ListNode detectCycle(ListNode head) {
        ListNode first = head;
        ListNode second = head;
        boolean flag=false;
        while(second!=null&&second.next!=null) {  //无环为null返回
            first=first.next;
            second=second.next.next;
            if(first==second) {
                flag=true;
                break;
            }
        }
        if(flag==false)
            return null;
        else {
            first=head;
            while(first!=second) {
                first=first.next;
                second=second.next;
            }
            return first;
        }
    }

143. Reorder List

重排链表,这道题给我一种“妙啊”的感觉,后一半反排插入一开始不知道怎么办,甚至想到了hash,讨论区的做法是,先把后一半反转,再逐个插入。

public void reorderList(ListNode head) {
        if(head==null||head.next==null||head.next.next==null) return;
        ListNode fast=head;
        ListNode slow=head;
        //找到一半
        while(fast!=null&&fast.next!=null) {
            fast=fast.next.next;
            slow=slow.next;
        }
        //反转
        ListNode first = slow.next;
        ListNode second = first.next;
        slow.next=null;
        first.next=null;
        while(second!=null) {
            ListNode third = second.next;
            second.next=first;
            first=second;
            second=third;
        }
        //逐个插入
        ListNode tmp=head;
        ListNode next=null;
        while(first!=null) {
            next=first.next;
            first.next=tmp.next;
            tmp.next=first;
            tmp=tmp.next.next;
            first=next;
        }
    }

148. Sort List

在O(nlogn)时间内排序,归并排序加递归,将链表分为两半,递归排序,再将这两半排好序的链表合并在一起。

public ListNode sortList(ListNode head) {
        if(head==null||head.next==null) return head;
        ListNode fast = head;
        ListNode slow = head;
        //链表分半
        while(fast.next!=null&&fast.next.next!=null) {
            fast=fast.next.next;
            slow=slow.next;
        }
        //递归排序
        ListNode tmp=slow.next;
        slow.next=null;
        ListNode left=sortList(head);
        ListNode right=sortList(tmp);
        //合并
        ListNode blank=new ListNode(0);
        tmp=blank;
        while(left!=null&&right!=null) {
            if(left.val<right.val) {
                tmp.next=left;
                left=left.next;
                tmp=tmp.next;
            }else {
                tmp.next=right;
                right=right.next;
                tmp=tmp.next;
            }
        }
        if(left!=null)
            tmp.next=left;
        if(right!=null)
            tmp.next=right;
        return blank.next;
    }
总结:

在链表头部添加空头以消除头部特殊判断比较常见,双指针问题可用于倒数k个或将链表元素分半。递归和hashmap也比较常见。

猜你喜欢

转载自blog.csdn.net/wonner_/article/details/79766037
今日推荐