Leetcode之链表(一)

目录

1.linked-list-cycle

2.linked-list-cycle-ii

3.partition-list

4.reverse-linked-list-ii

5.reverse-nodes-in-k-group

6.rotate-list

7.reorder-list

8.swap-nodes-in-pairs

9.convert-sorted-list-to-binary-search-tree

10.remove-nth-node-from-end-of-list


1.linked-list-cycle

题目:判断给定的链表中是否有环,满足不使用额外的空间

分析:利用快慢指针,如果快慢指针能相遇则说明有环

   public boolean hasCycle(ListNode head) {
        ListNode low = head;
        ListNode quick = head;
        while(quick != null && quick.next != null){
            quick = quick.next.next;
            low = low.next;
            if(low == quick)
                return true;
        }
        return false;
    }

2.linked-list-cycle-ii

题目:对于一个给定的链表,返回环的入口节点,如果没有环,返回null

分析:见剑指offer面试题23 https://blog.csdn.net/Nibaby9/article/details/104050540

3.partition-list

题目:给出一个链表和一个值x,以x为参照将链表划分成两部分,使所有小于x的节点都位于大于或等于x的节点之前。两个部分之内的节点之间要保持的原始相对顺序。例如:给出1->4->3->2->5->2和x = 3,返回1->2->2->4->3->5.

分析:新建立两个结点,将小于x的结点与大于等于x的结点分别插到这两个结点之后,形成两条链表,最后将两条链表连起来即可。

    public ListNode partition(ListNode head, int x) {
        ListNode head1 = new ListNode(0);
        ListNode head2 = new ListNode(0);
        ListNode cur = head,cur1 = head1,cur2 = head2;
        while(cur != null){
            if(cur.val < x){
                cur1.next = cur;
                cur1 = cur1.next;
            }
            else{
                cur2.next = cur;
                cur2 = cur2.next;
            }
            cur = cur.next;
        }
        cur1.next = head2.next;
        cur2.next = null;
        return head1.next;
    }

4.reverse-linked-list-ii

题目:将一个链表m位置到n位置之间的区间反转,要求使用原地算法,并且在一次扫描之内完成反转。例如:给出的链表为1->2->3->4->5->NULL, m = 2 ,n = 4,返回1->4->3->2->5->NULL。注意:给出的m,n满足以下条件:1 ≤ m ≤ n ≤ 链表长度

分析:定义两个指针,指针pre指向链表开始反转的前一个位置,指针start指向链表反转的第一个位置。每次删除start的后一个节点,再该结点插入pre后面,需删除n-m次即可。注意:链表的头结点可能会发生变化,需要创建一个新节点来指向链表的头结点。

翻转链表类似题见剑指offer面试题24 https://blog.csdn.net/Nibaby9/article/details/104050540

    public ListNode reverseBetween(ListNode head, int m, int n){
        ListNode preHead = new ListNode(0);//方便返回链表头结点,修改后的头结点有可能不是head
        preHead.next = head;//勿漏
        ListNode pre = preHead;
        ListNode start = head;
        for(int i = 1;i < m;i++){
            pre = start;
            start = start.next;
        }
        for(int i = 1;i <= n - m;i++) {//需要删n-m次
            ListNode temp = start.next;
            start.next = temp.next;
            temp.next = pre.next;
            pre.next = temp;
        }
        return preHead.next;
    }

5.reverse-nodes-in-k-group

题目:将给出的链表中的节点每k个一组翻转,返回翻转后的链表。如果链表中的节点数不是k的倍数,将最后剩下的节点保持原样。你不能更改节点中的值,只能更改节点本身。只允许使用常数级的空间。例如:给定的链表是1->2->3->4->5,对于 k = 2, 你应该返回 2->1->4->3->5;对于 k = 3, y你应该返回 3->2->1->4->5

分析:递归。将前k个节点与剩下节点断开,翻转前k个节点,递归求解剩下节点,再将两条链表合并即可。

    public ListNode reverseKGroup(ListNode head, int k) {
        ListNode end = head;
        int index = 1;
        while(index < k && end != null){
            end = end.next;
            index++;
        }
        if(end == null || index < k)
            return head;
        ListNode head2 = end.next;
        end.next = null;
        head2 = reverseKGroup(head2,k);
        ListNode head1 = reverse(head);
        head.next = head2;
        return head1;
    }

    private ListNode reverse(ListNode head) {
        ListNode cur = head,pre = null;
        while(cur != null){
            ListNode temp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = temp;
        }
        return pre;
    }

6.rotate-list

题目:将给定的链表向右转动k个位置,k是非负数。例如:给定1->2->3->4->5->null , k=2,返回4->5->1->2->3->null。

分析:特别注意k可能大于链表长度!!!因此k = k%len。将尾结点next指针指向首节点,形成一个环,接着往后跑len-k步,就是所需链表的尾结点,从这断开链表即可。

    public ListNode rotateRight(ListNode head, int n) {
        if (head == null || head.next == null || n == 0)
            return head;
        int len = 1;
        ListNode tail = head;
        while(tail.next != null){
            len++;
            tail = tail.next;
        }
        tail.next = head;//首尾相连形成环
        for(int i = 0;i < len - n % len;i++){//注意n有可能大于链表长度
            tail = tail.next;
        }
        head = tail.next;
        tail.next = null;
        return head;
    }

7.reorder-list

题目:将给定的单链表L: L 0→L 1→…→L n-1→L n,重新排序为: L 0→L n →L 1→L n-1→L 2→L n-2→…要求使用原地算法,并且不改变节点的值。例如:对于给定的单链表{1,2,3,4},将其重新排序为{1,4,2,3}.

分析:将链表分成两半,然后将后半部分翻转,最后拼接两个链表即可。

  public void reorderList(ListNode head) {
        if(head == null)
            return;
        //将链表从中间断开
        ListNode mid = findMid(head);
        ListNode head2 = mid.next;
        mid.next = null;
        //将链表的前半部分和反转后的后半部分合并
        ListNode cur1 = head,cur2 = reverse(head2);
        while(cur1 != null && cur2 != null){
            ListNode temp1 = cur1.next;
            ListNode temp2 = cur2.next;
            cur1.next = cur2;
            cur2.next = temp1;
            cur1 = temp1;
            cur2 = temp2;
        }
    }

    private ListNode reverse(ListNode head) {
        ListNode pre = null,cur = head;
        while(cur != null){
            ListNode temp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = temp;
        }
        return pre;
    }

    private ListNode findMid(ListNode head) {
        ListNode low = head,fast = head;
        while(fast != null && fast.next != null){
            low = low.next;
            fast = fast.next.next;
        }
        return low;
    }

8.swap-nodes-in-pairs

题目:将给定的链表中每两个相邻的节点交换一次,返回链表的头指针。例如,给出1->2->3->4,你应该返回链表2->1->4->3。你给出的算法只能使用常量级的空间。你不能修改列表中的值,只能修改节点本身。

分析:递归求解即可。

    public ListNode swapPairs(ListNode head) {
        if(head == null || head.next == null)
            return head;
        ListNode temp = head.next;
        head.next = swapPairs(temp.next);
        temp.next = head;
        return temp;
    }

9.convert-sorted-list-to-binary-search-tree

题目:给定一个单链表,其中的元素按升序排序,请将它转化成平衡二叉搜索树(BST)

分析:先利用快慢指针找到单链表的中间节点,然后以该节点为根结点,再把原链表断开,分为前后两个链表,递归调用原函数,分别为根结点的左右子树。注意参数的设计,传递的是链表的第一个结点和最后一个节点的next。

    public TreeNode sortedListToBST(ListNode head) {
         return toBST(head,null);
    }

    private TreeNode toBST(ListNode head, ListNode tail) {
        if(head == tail)
            return null;
        ListNode quick = head;
        ListNode low = head;
        while(quick != tail && quick.next != tail){
            low = low.next;
            quick = quick.next.next;
        }
        TreeNode root = new TreeNode(low.val);
        root.left = toBST(head,low);
        root.right = toBST(low.next,tail);
        return root;
    }

10.remove-nth-node-from-end-of-list

题目:给定一个链表,删除链表的倒数第n个节点并返回链表的头指针。例如, 给出的链表为:1->2->3->4->5, n= 2.↵↵ 删除了链表的倒数第n个节点之后,链表变为1->2->3->5.备注:题目保证n一定是合法的;请尝试只用一步操作完成该功能

分析:删除倒数第n个节点需先找出倒数第n+1个节点。倒数数第n+1个节点也就是第len-n个节点,采用快慢指针,快指针先走出n步,随后两个指针同时前进,当快指针到达链表尾部时,慢指针刚好到达倒数第n+1个节点的位置。注意删除节点为链表头结点的情况。类似题见剑指offer面试题22 https://blog.csdn.net/Nibaby9/article/details/104050540

   public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode preHead = new ListNode(0);
        preHead.next = head;
        ListNode quick = preHead;
        ListNode slow = preHead;
        for(int i = 0;i < n;i++)
            quick = quick.next;
        while(quick.next != null){
            slow = slow.next;
            quick = quick.next;
        }
        slow.next = slow.next.next;
        return preHead.next;
    }

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值