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;
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章