[LeetCode-150 古典的な面接の質問 - 14 日目]

 

目次

19. リンクリストの下から N 番目のノードを削除します。

 82.ソート済み連結リストⅡの重複要素の削除

 61. リンクリストの回転

 86. 個別のリンクリスト

 146.LRUキャッシュ


19. リンクリストの下から N 番目のノードを削除します。

質問の意味:

リンク リストを指定すると、 n リンク リストの最後から 2 番目のノードを削除し、リンク リストの先頭ノードを返します。

【入力例】 head = [1,2,3,4,5],n=2

[出力サンプル][1,2,3,5]

問題解決のアイデア:

1. ダブル ポインター p および q、初期ハッシュはヘッド ノードを指します。

2. p と q の間の要素が n になるまで q を移動します

3. q がリンクリストの末尾で null を指すまで、p と q を同時に移動します。

4. p.next = p.next.next

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummyHead = new ListNode(0,head);
        ListNode p = dummyHead;
        ListNode q = head;
        for(int i=0; i< n; i++){
            q = q.next;
        }
        while(q != null){
            q = q.next;
            p = p.next;
        }
        p.next = p.next.next;
        ListNode ans = dummyHead.next;
        return ans;

    }
}

時間: 100.00% を達成

メモリ: 64.22% の差

 82.ソート済み連結リストⅡの重複要素の削除

質問の意味:

ソートされたリンク リストの先頭を指定して head 、 元のリンク リスト内の重複する番号を持つすべてのノードを削除し、異なる番号だけを残します 。ソートされたリンクリストを返します  。

[入力例] head = [1,1,1,2,3]

[出力サンプル][2,3]

問題解決のアイデア:

1. リンクリストのヘッドノードを指すダムノードを定義します。

2. ポインタ cur はダムノードを指し、リンクリストを横断します。

3. cur.next.val == cur.next.next.val の場合、同じ要素 x を持つすべての cur.next 以降のノードを削除します (x=cur.next.val)。

4. cur.next が空のノードになるか、要素の値が x に等しくなるまで、重複要素の削除を続けます。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        if(head == null){
            return head;
        }
        ListNode dummy = new ListNode(0,head);
        ListNode cur = dummy;
        while(cur.next != null && cur.next.next != null){
            if(cur.next.val == cur.next.next.val){
                int x = cur.next.val;
                while(cur.next != null && cur.next.val == x){
                    cur.next = cur.next.next;//不断跳过重复值的数
                }
            }else{
                cur = cur.next;//继续往下遍历
            }
        }
        return dummy.next;//指向head
    }
}

時間: 100.00% を達成

メモリ: 86.54% 上回る

 61. リンクリストの回転

質問の意味:

リンク リストのヘッド ノードが与えられ head 、リンク リストを回転し、リンク リストの各ノードを右に移動します k 

[入力例] head = [1,2,3,4,5],k=2

[出力サンプル][4,5,1,2,3]

問題解決のアイデア:

1. リンクリストのヘッドノードを指すダムノードを定義します。

2. リンク リストを走査し、リンク リストの長さをカウントし、k%n までの移動数を最適化します。

3. 元のリンク リストの閉ループを形成し、count = nk%n を計算します。これは、現在のノードから開始して count 回トラバースすることで末尾ノードを見つけることができることを意味します。

4. count = 0 になるまでポインタを動かし続けます。このとき、新しいリンク リストの先頭ノードとして、dummy.next を指す新しいノードを定義します。Dummy.next には、リンク切断を実現するために null が割り当てられます。

 

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode rotateRight(ListNode head, int k) {
        if(k == 0 || head==null || head.next == null){
            return head;
        }
        //一次遍历,统计链表的长度n,移动k次相当于移动k%n次;
        int n = 1;
        ListNode dummy = head;
        while(dummy.next !=null){
            dummy = dummy.next;
            ++n;
        }
        int count = n - k % n;
        if(count == n){
            return head;
        }
        dummy.next = head;//形成闭环
        while(count-- > 0){
            dummy = dummy.next;
        }
        ListNode result = dummy.next;
        dummy.next = null;
        return result;

    }
}

時間: 100.00% を達成

メモリ: 68.97% 上回る

 86. 個別のリンクリスト

質問の意味:

リンク リストのヘッド ノード head と特定の値が与えられています。以下のすべての ノードが 以上の ノードの前に表示される ようにリンク リストを分割してください  x x x

 両方のパーティション内の各ノードの初期の相対位置を保存する必要があります 。

【入力例】 head = [1,4,3,2,5,2],x=3

[出力サンプル][1,2,2,4,3,5]

問題解決のアイデア:

1. 2 つのリンク リストを使用し、1 つは x 未満のノードを保存し、もう 1 つは x 以上のノードを保存し、2 つのリンク リストを結合します。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode partition(ListNode head, int x) {
        ListNode minNext = new ListNode(0);
        ListNode minhead = minNext;
        ListNode maxNext = new ListNode(0);
        ListNode maxhead = maxNext;

        while(head!=null){
            if(head.val < x){
                minNext.next = head;
                minNext = minNext.next;
            }else{
                maxNext.next = head;
                maxNext = maxNext.next;
            }
            head = head.next;
        }
        maxNext.next = null;
        minNext.next = maxhead.next;
        return minhead.next;
    }
}

時間: 100.00% を達成

メモリ: 20.49% の差

 146.LRUキャッシュ

質問の意味:

LRU(最も最近使用されていない)キャッシュ制約を満たすデータ構造を設計および実装してください   。

実装 LRUCache クラス:

  • LRUCache(int capacity) 容量として 正の整数 を使用して capacity LRU キャッシュを初期化します。
  • int get(int key) キーワードがキャッシュに存在する場合は key キーワードの値を返し、存在しない場合はその値を返します -1 。
  • void put(int key, int value) キーワードが key すでに存在する場合は、そのデータ値を変更し value 、キーワードが存在しない場合は、グループをキャッシュに挿入します key-value 。挿入操作によりキーワードの数を超えた場合は 、 最も古い未使用のキーワードを削除するcapacity 必要があります 。

関数 get を put 実行する必要がある O(1) 平均時間複雑さ。

【入力サンプル】

["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"] [[2], [1, 1 
] ]、[2、2]、[1]、[3、3]、[2]、[4、4]、[1]、[3]、[4]]

【出力サンプル】

[ヌル、ヌル、ヌル、1、ヌル、-1、ヌル、-1、3、4]
LRUCacheの説明
lRUCache = new LRUCache(2); 
lRUCache.put(1, 1); // キャッシュは{1=1} 
lRUCache.put(2, 2); // キャッシュは{1=1, 2 =2} 
lRUCache.get(1); // 1 を返します
lRUCache.put(3, 3); // この操作はキーワード 2 を無効にし、キャッシュは {1=1, 3=3} 
lRUCache.get(2) ); // 戻り値 -1 (見つかりません) 
lRUCache.put(4, 4); // この操作はキーワード 1 を無効にし、キャッシュは {4=4, 3=3} 
lRUCache.get(1); //戻り値 - 1 (見つかりません) 
lRUCache.get(3); // 3 を返します
lRUCache.get(4); // 4 を返します

問題解決のアイデア: ハッシュ テーブル + 二重リンク リスト

1. 二重リンク リストには、使用される順序でキーと値のペアが格納されます。先頭に最も近いキーと値のペアが最後に使用され、末尾に最も近いキーと値のペアが最も長く使用されていません。

2. ハッシュ テーブル キャッシュ データのキーは、二重リンク リスト内のその位置にマッピングされます。

3. 位置決めにハッシュ テーブルを使用し、二重リンク リスト内のキャッシュ アイテムの位置を見つけて、それを二重リンク リストの先頭に移動します。キーがハッシュ テーブルに格納されていない場合は、-1 または at を返します。リンクされたリストの先頭 新しいノードを作成します。

public class LRUCache {
    private Map<Integer,DLinkedNode> cache = new HashMap<Integer,DLinkedNode>();
    private int size;
    private int capacity;
    private DLinkedNode head,tail;

    public LRUCache(int capacity) {
        this.size = 0;
        this.capacity = capacity;
        head = new DLinkedNode();
        tail = new DLinkedNode();
        head.next = tail;
        tail.prev = head;
    }
    
    public int get(int key) {
        DLinkedNode node = cache.get(key);
        if(node == null){
            //链表中不存在此值
            return -1;
        }
        //存在,将其移动到双向链表的头部
        moveToHead(node);
        return node.value;
    }
    
    public void put(int key, int value) {
        DLinkedNode node = cache.get(key);
        if(node == null){
            //如果key不存着,要创建一个新节点
            //需要判断插入之后长度是否会超过容量
            DLinkedNode newNode = new DLinkedNode(key,value);
            cache.put(key,newNode);
            addToHead(newNode);
            ++size;//每加进来一个元素,size++
            if(size > capacity){
                //删除尾部节点和哈希表中的对应项
                DLinkedNode tail = removeTail();
                cache.remove(tail.key);
                --size;
            }
        }else{
            //key存在,哈希表定位,修改value,移到头部
            node.value = value;
            moveToHead(node);
        }
    }

    private void addToHead(DLinkedNode node){
        //添加到双向链表头部
        node.prev = head;
        node.next = head.next;
        head.next.prev = node;
        head.next = node;
    }

    private void removeNode(DLinkedNode node){
        //从当前位置移走
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }

    private void moveToHead(DLinkedNode node){
        removeNode(node);
        addToHead(node);
    }

    private DLinkedNode removeTail(){
        DLinkedNode node = tail.prev;
        removeNode(node);
        return node;
    }
}


class DLinkedNode{
    int key;
    int value;
    DLinkedNode prev;
    DLinkedNode next;
    public DLinkedNode(){}
    public DLinkedNode(int key, int value){
        this.key = key;
        this.value = value;
    }
}
/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache obj = new LRUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */

タイム: 敗北 23.27%

メモリ: 97.38% を達成

おすすめ

転載: blog.csdn.net/qq_37998848/article/details/132488098