目次
19. リンクリストの下から N 番目のノードを削除します。
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% を達成