6.30 二刷二叉树
This commit is contained in:
parent
b814779b7d
commit
6976c55204
@ -1,105 +0,0 @@
|
||||
package linkedlist;
|
||||
/**
|
||||
* 题目: 146. LRU 缓存 (LRUCache)
|
||||
* 描述:请你设计并实现一个满足 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) 的平均时间复杂度运行。
|
||||
|
||||
示例 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]]
|
||||
输出
|
||||
[null, null, null, 1, null, -1, null, -1, 3, 4]
|
||||
|
||||
* 链接:https://leetcode.cn/problems/lru-cache/
|
||||
*/
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class LRUCache {
|
||||
class DLinkedNode {
|
||||
int key;
|
||||
int value;
|
||||
DLinkedNode prev;
|
||||
DLinkedNode next;
|
||||
public DLinkedNode() {}
|
||||
public DLinkedNode(int _key, int _value) {key = _key; value = _value;}
|
||||
}
|
||||
|
||||
private Map<Integer, DLinkedNode> cache = new HashMap<>();
|
||||
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;
|
||||
}
|
||||
// 如果 key 存在,先通过哈希表定位,再移到头部
|
||||
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;
|
||||
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 res = tail.prev;
|
||||
removeNode(res);
|
||||
return res;
|
||||
}
|
||||
}
|
67
src/main/java/linkedlist/MergeKLists.java
Normal file
67
src/main/java/linkedlist/MergeKLists.java
Normal file
@ -0,0 +1,67 @@
|
||||
package linkedlist;
|
||||
|
||||
/**
|
||||
* 题目: 23. 合并 K 个升序链表 (mergeKLists)
|
||||
* 描述:给你一个链表数组,每个链表都已经按升序排列。
|
||||
* 请你将所有链表合并到一个升序链表中,返回合并后的链表。
|
||||
* 链接:https://leetcode.cn/problems/merge-k-sorted-lists
|
||||
* <p>
|
||||
* 输入:lists = [[1,4,5],[1,3,4],[2,6]]
|
||||
* 输出:[1,1,2,3,4,4,5,6]
|
||||
* 解释:链表数组如下:
|
||||
* [
|
||||
* 1->4->5,
|
||||
* 1->3->4,
|
||||
* 2->6
|
||||
* ]
|
||||
* 将它们合并到一个有序链表中得到。
|
||||
* 1->1->2->3->4->4->5->6
|
||||
*/
|
||||
//二刷不会
|
||||
public class MergeKLists {
|
||||
//两两合并
|
||||
public ListNode mergeKLists2(ListNode[] lists) {
|
||||
ListNode ans = null;
|
||||
for (int i = 0; i < lists.length; ++i) {
|
||||
ans = mergeTwoLists(ans, lists[i]);
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
public ListNode mergeTwoLists(ListNode a, ListNode b) {
|
||||
if (a == null || b == null) {
|
||||
return a != null ? a : b;
|
||||
}
|
||||
ListNode head = new ListNode(0);
|
||||
ListNode tail = head, aPtr = a, bPtr = b;
|
||||
while (aPtr != null && bPtr != null) {
|
||||
if (aPtr.val < bPtr.val) {
|
||||
tail.next = aPtr;
|
||||
aPtr = aPtr.next;
|
||||
} else {
|
||||
tail.next = bPtr;
|
||||
bPtr = bPtr.next;
|
||||
}
|
||||
tail = tail.next;
|
||||
}
|
||||
tail.next = (aPtr != null ? aPtr : bPtr);
|
||||
return head.next;
|
||||
}
|
||||
|
||||
|
||||
//分治合并
|
||||
public ListNode mergeKLists(ListNode[] lists) {
|
||||
return merge(lists, 0, lists.length - 1);
|
||||
}
|
||||
|
||||
public ListNode merge(ListNode[] lists, int l, int r) {
|
||||
if (l == r) {
|
||||
return lists[l];
|
||||
}
|
||||
if (l > r) {
|
||||
return null;
|
||||
}
|
||||
int mid = (l + r) >> 1;
|
||||
return mergeTwoLists(merge(lists, l, mid), merge(lists, mid + 1, r));
|
||||
}
|
||||
}
|
@ -6,8 +6,20 @@ package tree;
|
||||
* 两节点之间路径的 长度 由它们之间边数表示。
|
||||
|
||||
* 链接:https://leetcode.cn/problems/diameter-of-binary-tree/
|
||||
|
||||
1
|
||||
/ \
|
||||
2 3
|
||||
/ \
|
||||
4 5
|
||||
/ \
|
||||
6 7
|
||||
/ \
|
||||
8 9
|
||||
/ \
|
||||
10 11
|
||||
不一定经过root!
|
||||
*/
|
||||
//二刷会做
|
||||
public class DiameterOfBinaryTree {
|
||||
|
||||
private int maxDiameter = 0;
|
||||
|
@ -11,6 +11,7 @@ import java.util.List;
|
||||
* 链接:https://leetcode.cn/problems/binary-tree-inorder-traversal/
|
||||
|
||||
*/
|
||||
//二刷会做
|
||||
//递归会 迭代需记一下
|
||||
public class InorderTraversal {
|
||||
//递归
|
||||
@ -29,6 +30,21 @@ public class InorderTraversal {
|
||||
inorder(root.right, res);
|
||||
}
|
||||
|
||||
public List<Integer> inorderTraversal2(TreeNode root) {
|
||||
List<Integer> res=new ArrayList<>();
|
||||
Deque<TreeNode>stack=new ArrayDeque<>();
|
||||
while (root!=null || !stack.isEmpty()){
|
||||
while (root!=null){
|
||||
stack.push(root);
|
||||
root=root.left;
|
||||
}
|
||||
root=stack.pop();
|
||||
res.add(root.val);
|
||||
root=root.right;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
//迭代+栈
|
||||
public List<Integer> inorderTraversal1(TreeNode root) {
|
||||
List<Integer> res = new ArrayList<Integer>();
|
||||
|
@ -6,7 +6,24 @@ package tree;
|
||||
* 链接:https://leetcode.cn/problems/invert-binary-tree/
|
||||
|
||||
*/
|
||||
//二刷会做
|
||||
public class InvertTree {
|
||||
void dfs(TreeNode root){
|
||||
if(root!=null) {
|
||||
TreeNode tp;
|
||||
tp = root.left;
|
||||
root.left = root.right;
|
||||
root.right = tp;
|
||||
dfs(root.left);
|
||||
dfs(root.right);
|
||||
}
|
||||
}
|
||||
public TreeNode invertTree2(TreeNode root) {
|
||||
dfs(root);
|
||||
return root;
|
||||
}
|
||||
|
||||
//先调整父节点,再调子节点
|
||||
public void invert(TreeNode root){
|
||||
if(root!=null){
|
||||
TreeNode temp;
|
||||
@ -21,6 +38,7 @@ public class InvertTree {
|
||||
invert(root);
|
||||
return root;
|
||||
}
|
||||
//先调子 再调父节点
|
||||
public TreeNode invertTree(TreeNode root) {
|
||||
if (root == null) {
|
||||
return null;
|
||||
|
@ -11,8 +11,10 @@ import java.util.Queue;
|
||||
|
||||
*/
|
||||
//不会做,递归和迭代都写一下
|
||||
//二刷不会
|
||||
public class IsSymmetric {
|
||||
|
||||
//递归
|
||||
public boolean isSymmetric(TreeNode root) {
|
||||
// 如果根节点为空,则认为是对称的
|
||||
if (root == null) {
|
||||
@ -40,6 +42,7 @@ public class IsSymmetric {
|
||||
&& isMirror(left.right, right.left);
|
||||
}
|
||||
|
||||
//层序遍历
|
||||
public boolean isSymmetric1(TreeNode root) {
|
||||
if (root == null) {
|
||||
return true;
|
||||
|
@ -15,7 +15,9 @@ import java.util.List;
|
||||
* 链接:https://leetcode.cn/problems/validate-binary-search-tree/
|
||||
|
||||
*/
|
||||
//二刷会做
|
||||
public class IsValidBST {
|
||||
|
||||
//递归
|
||||
public boolean helper(TreeNode node, long lower, long upper) {
|
||||
if (node == null) {
|
||||
@ -30,6 +32,7 @@ public class IsValidBST {
|
||||
return helper(root, Long.MIN_VALUE, Long.MAX_VALUE);
|
||||
}
|
||||
|
||||
|
||||
//中序遍历
|
||||
public void dfs(TreeNode root,List<Integer>list){
|
||||
if(root!=null){
|
||||
|
@ -8,20 +8,24 @@ import java.util.List;
|
||||
* 描述:给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 小的元素(从 1 开始计数)。
|
||||
|
||||
* 链接:https://leetcode.cn/problems/kth-smallest-element-in-a-bst/
|
||||
|
||||
进阶:如果二叉搜索树经常被修改(插入/删除操作)并且你需要频繁地查找第 k 小的值,你将如何优化算法?
|
||||
*/
|
||||
//二刷会做
|
||||
public class KthSmallest {
|
||||
//中序遍历
|
||||
public void dfs(TreeNode root, List<Integer> list){
|
||||
if(root!=null){
|
||||
dfs(root.left,list);
|
||||
list.add(root.val);
|
||||
dfs(root.right,list);
|
||||
}
|
||||
}
|
||||
private int k, ans;
|
||||
public int kthSmallest(TreeNode root, int k) {
|
||||
List<Integer>list=new ArrayList<>();
|
||||
dfs(root,list);
|
||||
return list.get(k-1);
|
||||
this.k = k;
|
||||
dfs(root);
|
||||
return ans;
|
||||
}
|
||||
private void dfs(TreeNode node) {
|
||||
if (node == null) return;
|
||||
dfs(node.left);
|
||||
if (--k == 0) { // 访问到第 k 个
|
||||
ans = node.val;
|
||||
return; // 提前结束递归
|
||||
}
|
||||
dfs(node.right);
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import java.util.Queue;
|
||||
* 链接:https://leetcode.cn/problems/binary-tree-level-order-traversal/
|
||||
|
||||
*/
|
||||
//二刷会做
|
||||
public class LevelOrder {
|
||||
public List<List<Integer>> levelOrder(TreeNode root) {
|
||||
List<List<Integer>>res=new ArrayList<>();
|
||||
|
@ -13,6 +13,7 @@ import java.util.Queue;
|
||||
* 链接:https://leetcode.cn/problems/maximum-depth-of-binary-tree/
|
||||
|
||||
*/
|
||||
//二刷会做
|
||||
public class MaxDepth {
|
||||
//递归
|
||||
int dfs(TreeNode root){
|
||||
@ -23,6 +24,7 @@ public class MaxDepth {
|
||||
public int maxDepth1(TreeNode root) {
|
||||
return dfs(root);
|
||||
}
|
||||
|
||||
//bfs
|
||||
public int maxDepth(TreeNode root) {
|
||||
if (root == null) {
|
||||
|
@ -6,6 +6,7 @@ package tree;
|
||||
* 链接:https://leetcode.cn/problems/convert-sorted-array-to-binary-search-tree/
|
||||
|
||||
*/
|
||||
//二刷不会
|
||||
public class SortedArrayToBST {
|
||||
//分治
|
||||
TreeNode func(int left,int right ,int[] nums){
|
||||
|
164
src/main/java/实现类功能/LRUCache.java
Normal file
164
src/main/java/实现类功能/LRUCache.java
Normal file
@ -0,0 +1,164 @@
|
||||
package 实现类功能;
|
||||
/**
|
||||
* 题目: 146. LRU 缓存 (LRUCache)
|
||||
* 描述:请你设计并实现一个满足 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) 的平均时间复杂度运行。
|
||||
|
||||
示例 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]]
|
||||
输出
|
||||
[null, null, null, 1, null, -1, null, -1, 3, 4]
|
||||
|
||||
* 链接:https://leetcode.cn/problems/lru-cache/
|
||||
*/
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
//二刷不会 学习
|
||||
|
||||
/**
|
||||
* 对于 get 操作,首先判断 key 是否存在:
|
||||
* 如果 key 不存在,则返回 −1;
|
||||
* 如果 key 存在,则 key 对应的节点是最近被使用的节点。通过哈希表定位到该节点在双向链表中的位置,并将其移动到双向链表的头部,最后返回该节点的值。
|
||||
*
|
||||
* 对于 put 操作,首先判断 key 是否存在:
|
||||
* 如果 key 不存在,使用 key 和 value 创建一个新的节点,在双向链表的头部添加该节点,并将 key 和该节点添加进哈希表中。然后判断双向链表的节点数是否超出容量,如果超出容量,则删除双向链表的尾部节点,并删除哈希表中对应的项;
|
||||
* 如果 key 存在,则与 get 操作类似,先通过哈希表定位,再将对应的节点的值更新为 value,并将该节点移到双向链表的头部。
|
||||
*
|
||||
*
|
||||
* 注意,key和value不必相等
|
||||
*/
|
||||
public class LRUCache {
|
||||
|
||||
/* ----------------------------- 链表节点定义 ----------------------------- */
|
||||
|
||||
/**
|
||||
* 双向链表节点
|
||||
*/
|
||||
class DLinkedNode {
|
||||
int key; // 保存 key:便于淘汰节点时同步从 cache 中删除
|
||||
int value; // 保存 value
|
||||
DLinkedNode prev; // 前驱
|
||||
DLinkedNode next; // 后继
|
||||
|
||||
public DLinkedNode() {}
|
||||
|
||||
public DLinkedNode(int _key, int _value) {
|
||||
key = _key;
|
||||
value = _value;
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------- 成员变量 ----------------------------- */
|
||||
|
||||
private final Map<Integer, DLinkedNode> cache = new HashMap<>(); // 哈希表
|
||||
private int size; // 当前键值对数量
|
||||
private final int capacity; // 最大容量
|
||||
|
||||
// 伪头、伪尾(固定不动)
|
||||
private final DLinkedNode head;
|
||||
private final DLinkedNode tail;
|
||||
|
||||
/* ----------------------------- 构造函数 ----------------------------- */
|
||||
|
||||
/**
|
||||
* @param capacity 缓存最大容量 (正整数)
|
||||
*/
|
||||
public LRUCache(int capacity) {
|
||||
this.size = 0;
|
||||
this.capacity = capacity;
|
||||
|
||||
// 创建伪头、伪尾并相连
|
||||
head = new DLinkedNode();
|
||||
tail = new DLinkedNode();
|
||||
head.next = tail;
|
||||
tail.prev = head;
|
||||
}
|
||||
|
||||
/* ----------------------------- 公共接口 ----------------------------- */
|
||||
|
||||
/**
|
||||
* @param key 查询的键
|
||||
* @return 若存在则返回对应 value,否则返回 -1
|
||||
*/
|
||||
public int get(int key) {
|
||||
DLinkedNode node = cache.get(key);
|
||||
if (node == null) { // 不存在
|
||||
return -1;
|
||||
}
|
||||
// 存在:移动到链表头部(标记为最近使用)
|
||||
moveToHead(node);
|
||||
return node.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入或更新键值对
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
*/
|
||||
public void put(int key, int value) {
|
||||
DLinkedNode node = cache.get(key);
|
||||
|
||||
if (node == null) {
|
||||
/* ---------- 新键 ---------- */
|
||||
DLinkedNode newNode = new DLinkedNode(key, value);
|
||||
cache.put(key, newNode); // 哈希表记录
|
||||
addToHead(newNode); // 链表头插
|
||||
++size;
|
||||
|
||||
// 超容量:弹出尾节点(最久未使用)
|
||||
if (size > capacity) {
|
||||
DLinkedNode tail = removeTail(); // 真尾节点
|
||||
cache.remove(tail.key); // 同步删除哈希表项
|
||||
--size;
|
||||
}
|
||||
} else {
|
||||
/* ---------- 已存在键:更新值并提到头部 ---------- */
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 弹出尾部节点(真尾 = 伪尾的前驱)
|
||||
* @return 被移除的节点
|
||||
*/
|
||||
private DLinkedNode removeTail() {
|
||||
DLinkedNode res = tail.prev;
|
||||
removeNode(res);
|
||||
return res;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user