leetcode之链表

leetcode之链表

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

1

/*
Sort a linked list in O(n log n) time using constant space complexity.
*/
/*
* 此题两个要点,一是在要求的时间复杂度下,要想到是归并排序,他的空间复杂度用链表是O(1),
* 二是寻找链表的中点用快慢指针,然后注意一下链表指针指向的细节问题(别弄错)就可以了
* */
public class Test {
    public ListNode sortList(ListNode head) {
        //空节点或一个节点直接返回
        if(head==null||head.next==null){
            return head;
        }
        ListNode slow = head;
        ListNode fast = head;
        //快慢指针慢指针是中点
        while(fast.next!=null&&fast.next.next!=null){
            slow = slow.next;
            fast = fast.next.next;
        }
        ListNode midNext = slow.next;
        //以中点为界,拆分成两个链表
        slow.next = null;
        //对两个单链表分别归并排序
        slow = sortList(midNext);
        head = sortList(head);
        return merge(head,slow);

    }

    private ListNode merge(ListNode l1, ListNode l2) {
        //最终结果的指针
        ListNode result = null;
        //先确定首节点
        if (l1.val<l2.val){
            result = l1;
            l1 = l1.next;
        }else {
            result = l2;
            l2 = l2.next;
        }
        //临时引用方便merge
        ListNode temp = result;
        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;
        }
        //最终剩的连上去
        if (l1!=null){
            temp.next = l1;
        }else {
            temp.next = l2;
        }
        return result;
    }
}

2

/*
Given a singly linked list L: L 0→L 1→…→L n-1→L n,
        reorder it to: L 0→L n →L 1→L n-1→L 2→L n-2→…
        You must do this in-place without altering the nodes' values.
        For example,
        Given{1,2,3,4}, reorder it to{1,4,2,3}.
*/
/*
* 这道题应该反应过来是用单链表的就地逆置,但是在传统的基础上改进一下,将原来的链表分为两部分,这里
* 自然想到用快慢指针,然后将后面的链表就地逆置,在将两个链表merge
* */
public class Test3 {
    public void reorderList(ListNode head) {
        //特殊情况直接返回
        if (head==null||head.next==null){
            return ;
        }
        //快慢指针直接找中点
        ListNode slow = head;
        ListNode fast = head;
        while(fast.next!=null&&fast.next.next!=null){
            fast = fast.next.next;
            slow = slow.next;
        }
        ListNode after = slow.next;
        //这里别忘将两个链表分开
        slow.next = null;

        //单链表就地逆置,基本功
        //pre指针永远是首节点,最初设为null
        ListNode pre = null;
        ListNode temp = null;
        while(after!=null){
            //取当前节点,当前节点后移
            temp = after;
            after = after.next;
            //当前节点插过去
            temp.next = pre;
            pre = temp;

        }

        //将两个链表合并
        ListNode temp2;
        ListNode cusor = head;
        while(pre!=null){
            temp2 = pre;
            pre = pre.next;
            temp2.next = cusor.next;
            cusor.next = temp2;
            cusor = temp2.next;
        }
    }


}

3

/*
Given a linked list, return the node where the cycle begins. If there is no cycle, returnnull.
Follow up:
Can you solve it without using extra space?
* */
/*这道题有一定的技巧性,但是对这种链表题比较熟悉的童鞋还是可以有思路的,最好画个图,一目了然,主要思路还是
用快慢指针判断是否有换环,如果有环,两指针必然相遇,求入环处,则将其中一个指针置于head,再将两个指针单步
同时进行,第二次相遇的位置就是所求
* */
public class Test4 {
    public ListNode detectCycle(ListNode head) {
        //特殊情况
        if (head==null||head.next==null){
            return null;
        }
        //快慢指针
        ListNode slow = head;
        ListNode fast = head;
        while(fast.next!=null&&fast.next.next!=null){
            slow = slow.next;
            fast = fast.next.next;
            //若有环,必然相遇
            if (slow==fast){
                //将slow置于head
                slow = head;
                //求第二次相遇的位置,返回
                while (slow!=fast){
                    slow = slow.next;
                    fast = fast.next;
                }
                return  slow;
            }

        }
        return null;
    }
}

4

/*
Reverse a linked list from position m to n. Do it in-place and in one-pass.
        For example:
        Given1->2->3->4->5->NULL, m = 2 and n = 4,
        return1->4->3->2->5->NULL.
        Note:
        Given m, n satisfy the following condition:
        1 ≤ m ≤ n ≤ length of list
*/
/*这道题是链表就地逆置的一个变形,要求是在指定位置进行就地逆置,这个比较简单,用个循环找到位置即可
需要注意,为了防止m是head,这里设置一个dummy,这也是对付这种链表问题的一个常用的技巧,将中间的部分就地逆置
后,将前后两部分连接起来就行了
* */
public class Test6 {
    public ListNode reverseBetween(ListNode head, int m, int n) {
            //设置一个哑变量,方便记录pre
            ListNode dummy = new ListNode(0);
            dummy.next = head;

            ListNode t1 = head;
            ListNode t2 = head;
            ListNode pre = dummy;
            //用循环找到m
            int t = 1;
            while(t!=m){

                t1 = t1.next;
                pre = pre.next;
                t += 1;

            }
            //记录前段链表的尾节点
            ListNode tt1 = t1;
            ListNode p = null;
            //中间部分就地逆置
            while (t!=n+1){
                ListNode temp = t1;
                t1 = t1.next;
                temp.next = p;
                p = temp;
                t += 1;
            }
            //前后三部分连接
            pre.next = p;
            tt1.next = t1;
            return dummy.next;

    }
}

5

/*
Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x.
        You should preserve the original relative order of the nodes in each of the two partitions.
        For example,
        Given1->4->3->2->5->2and x = 3,
        return1->2->2->4->3->5
*/
public class Test7 {
    public ListNode partition(ListNode head, int x) {
        if(head==null){
            return null;
        }
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        ListNode pre = dummy;
        ListNode t1 = head;
        while(t1!=null&&t1.val<x){
            pre = pre.next;
            t1 = t1.next;
        }
        ListNode t2 = t1;
        ListNode t3 = t1;
        while(t2!=null){
            if(t2.val<x){
                ListNode temp = t2;
                pre.next = temp;
                temp.next = t1;
                t2 = t2.next;
                t3.next = t2;
                t3 = t3.next;
            }else {
                t2 = t2.next;
            }
        }
        return dummy.next;
    }
}

6

/*Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list.
For example,
Given1->2->3->3->4->4->5, return1->2->5.
Given1->1->1->2->3, return2->3.
* */
public class Test8 {
    public static ListNode deleteDuplicates(ListNode head) {
        if(head==null||head.next==null){
            return head;
        }
        ListNode dummy = new ListNode(head.val-1);
        dummy.next = head;
        ListNode pre = dummy;
        ListNode t1 = head;
        while(t1!=null&&t1.next!=null){
            if(t1.val!=t1.next.val){
                pre = pre.next;
                t1 = t1.next;
            }else{
                ListNode temp = t1;
                //这个地方是真的坑,注意
                while(t1!=null&&t1.val==temp.val){
                    t1 = t1.next;
                }
                pre.next = t1;
            }
        }
        return  dummy.next;
    }
    public static void main(String[] agrs){

        ListNode head = new ListNode(1);
        ListNode w = new ListNode(1);
        head.next = w;
        ListNode r = deleteDuplicates(head);
        System.out.print(r);
    }
}

7

/*
Given a list, rotate the list to the right by k places, where k is non-negative.
For example:
Given1->2->3->4->5->NULLand k =2,
return4->5->1->2->3->NULL.
*/
/*这道题难度不大,但是容易少考虑情况,改了好几次才过,有的人用循环链表什么的,
但我感觉那种复杂度并不是很低啊,欢迎讨论,我的思路是遍历两次链表,第一次求出链表的长度,第二次找到
要翻转的位置,接上就行了,但是注意,这里的n可能大于链表长度,要求余数,另外有一种情况是n与链表长度相等
直接返回
* */
public class Test9 {
    public ListNode rotateRight(ListNode head, int n) {
       //这里有坑,注意顺序
        if(n==0||head==null||head.next==null){
            return head;
        }
        int i = 1;
        ListNode t = head;
        while(t.next!=null){
            i += 1;
            t = t.next;
        }
        //注意求余数
        n = n % i;
        //注意特殊情况
        if (n==0){
            return head;
        }
        ListNode t2 = head;
        for (int j = 0; j < i-n-1; j++) {
            t2 = t2.next;
        }
        ListNode newHead = t2.next;
        t2.next = null;
        t.next = head;
        return  newHead;
    }
}

8

/*
* Given a linked list, reverse the nodes of a linked list k at a time and return its modified list.
If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is.
You may not alter the values in the nodes, only nodes itself may be changed.
Only constant memory is allowed.
For example,
Given this linked list:1->2->3->4->5
For k = 2, you should return:2->1->4->3->5
For k = 3, you should return:3->2->1->4->5
*/
/*
这道题是一道很好的题,综合了链表改装问题的知识点,他是原来就地逆置链表的变形,这里也是用三个指针控制整个链表的
变形,关键在于用循环很好的控制体的要求,强烈建议做这种题画个图,不然指针一多,很容易乱
* */
public class Test10 {
    public ListNode reverseKGroup(ListNode head, int k) {
        //特殊情况不要忘
        if (head==null||head.next==null||k<=1){
            return head;
        }
        ListNode t = head;
        //求出链表长度
        int n = 1;
        while(t.next!=null){
            n += 1;
            t = t.next;
        }
        //设置哑结点
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        ListNode pre = dummy;
        ListNode cur = head;
        ListNode temp;
        //用连个循环控制
        for (int i = 0; i < n/k; i++) {
            for (int j = 0; j < k-1 ; j++) {
                //这里指针的变化最好画个图,容易出错
                temp = cur.next;
                cur.next = temp.next;
                temp.next = pre.next;
                pre.next = temp;
            }
            pre = cur;
            cur = cur.next;

        }
        return dummy.next;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值