leetcode 腾讯笔试面试题之链表题目总结(持续更新。。。)

一、合并两个有序链表(简单)

将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 

示例:

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

 1)java代码非递归实现(9ms  战胜96.25%):

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode pa, pb;
        ListNode pc = null;
        ListNode l3 = null;
        pa = l1;
        pb = l2;
        int i = 0 ;
        
        if(l1 == null) return l2;
        if(l2 == null) return l1;
        
        while((pa!=null)&&(pb!=null)){
            if(i == 0){
                if(pa.val <= pb.val){                    
                    pc = pa;
                    pa = pa.next;
                }else{                    
                    pc = pb;
                    pb = pb.next;
                }
                l3 = pc;
                i++;                
            }else{
                if(pa.val <= pb.val){
                    pc.next = pa;
                    pc = pa;
                    pa = pa.next;
                }else{
                    pc.next = pb;
                    pc = pb;
                    pb = pb.next;
                }
            }
        }        
        pc.next = pa==null ? pb:pa;
        return l3;
    }
}

2)java代码递归实现(15ms  战胜63.14%):

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {        
        if(l1 == null) return l2;
        if(l2 == null) return l1;
        
        if(l1.val <= l2.val){
            l1.next = mergeTwoLists(l1.next, l2);
            return l1;
        }else{
            l2.next = mergeTwoLists(l1, l2.next);
            return l2;
        }
    }
}

二、合并K个有序链表(困难):

合并 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。

示例:

输入:
[
  1->4->5,
  1->3->4,
  2->6
]
输出: 1->1->2->3->4->4->5->6

1) 方法一(29ms  战胜56.32%):

  将多个链表中的元素放到一个ArrayList中  —>  对此ArrayList进行排序  —>  将排好序的数组链表转换成 链表!

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        ListNode head = new ListNode(0);

        //将lists中所有元素放入一个数组中
        ArrayList arr = new ArrayList();
        for(ListNode eachlist : lists){
            while(eachlist!=null){
                arr.add(eachlist.val);
                eachlist = eachlist.next;
            }          
        }

        //对数组arr进行排序        
        Collections.sort(arr);

        //将数组转成链表
        ListNode result = head;
        for(int i=0; i<arr.size(); i++){
            ListNode newNode = new ListNode((int)arr.get(i));
            head.next = newNode;
            head = head.next;
        }
        return result.next;
    }
}

2)方法二(455ms  战胜8.53%):

遍历list数组,每次取K个链表的头结点进行比较,找寻出K个链表头结点中的最小节点,并将其从K个链表集中剔除,再将其添加到新的链表中,直到K个链表都为空为止。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        ListNode result = new ListNode(0);
        ListNode point = result;
        int min;
        int position = -1;
        while(true){
            min = Integer.MAX_VALUE;
            for(int i=0; i<lists.length; i++){
                if(lists[i] != null){
                    if(lists[i].val < min){
                        min = lists[i].val;
                        position = i;
                    }
                }
            }
            
            if(min == Integer.MAX_VALUE){
                break;
            }
            
            point.next = lists[position];
            point = point.next;
            lists[position] = lists[position].next;
        }
        
        return result.next;
    }
}

3)方法三(8ms   战胜99.72%):推荐此方法

  借鉴合并两个单链表的思想,对K个链表进行两两合并,得到最终结果!

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        if (lists.length == 0) return null;
        int n = lists.length;
        int k ;
        while(n>1){
            k = (n+1)/2;
            for(int i=0; i<n/2; i++){
                lists[i] = mergeTwoLists(lists[i], lists[i+k]);
            }
            n = k;
        }
        return lists[0];
    }
    
     public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if (l1 == null) return l2;
        if (l2 == null) return l1;
        if (l1.val < l2.val) {
            l1.next = mergeTwoLists(l1.next, l2);
            return l1;
        } else {
            l2.next = mergeTwoLists(l1, l2.next);
            return l2;
        }
    }
}

三、反转链表(非常重要,一定要非常熟练地写出来):

反转一个单链表。

示例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

 java实现反转链表(战胜100%用户)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        if(head == null || head.next == null) 
            return head;
        
        ListNode newHead = null;
        ListNode preNode = null;
        ListNode curNode = head;
        
        while(curNode != null){
            ListNode nextNode = curNode.next;
            if(nextNode == null){
                newHead = curNode;
            }
            curNode.next = preNode;           
            preNode = curNode;
            curNode = nextNode;        
        }
        return newHead;
    }
}

四、 旋转链表(中等):

给定一个链表,旋转链表,将链表每个节点向右移动 个位置,其中 是非负数。

示例 1:

输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL
解释:
向右旋转 1 步: 5->1->2->3->4->NULL
向右旋转 2 步: 4->5->1->2->3->NULL

示例 2:

输入: 0->1->2->NULL, k = 4
输出: 2->0->1->NULL

解释:
向右旋转 1 步: 2->0->1->NULL
向右旋转 2 步: 1->2->0->NULL
向右旋转 3 步: 0->1->2->NULL
向右旋转 4 步: 2->0->1->NULL

 java代码实现:

这个题可以用快慢指针来解,快指针先走k步,然后两个指针一起走,当快指针走到末尾时,慢指针的下一个位置是新的顺序的头结点,这样就可以旋转链表了。在这里需要考虑两个特殊情况,第一个就是当原链表为空时,直接返回NULL。第二个就是当k大于链表长度和k远远大于链表长度时,我们首先遍历一遍原链表得到链表长度size,然后k对size取余,这样k肯定小于size,就可以用上面的算法了。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode rotateRight(ListNode head, int k) {
        if(head == null) return head;
        
        int size = 0;
        ListNode cur = head;
        
        //遍历,得到链表的长度
        while(cur != null){
            size ++;
            cur = cur.next;
        }
        
        k %= size;
        ListNode fast,slow;
        fast = head;
        slow = head;
        
        //快指针先走 K 步
        for(int i=0; i<k; i++){
            fast = fast.next;
        }
        
        //快慢指针一起走,快指针到头,慢指针下一个元素就是旋转后的头结点
        while(fast.next != null){
            fast = fast.next;
            slow = slow.next;
        }
        
        fast.next = head;
        fast = slow.next;
        slow.next = null;
        return fast;
    }
}

猜你喜欢

转载自blog.csdn.net/fhy569039351/article/details/84670586