top代表题目的序号
二叉树的深度的求解:
top :104
class Solution {
public int maxDepth(TreeNode root) {
if(root==null)
return 0;
int left=maxDepth(root.left);
int right=maxDepth(root.right);
int max=Math.max(left,right)+1;
return max;
}
}
二叉树的直径:
top:543
class Solution {
int maxum=0;
public int diameterOfBinaryTree(TreeNode root) {
result(root);
return maxum;
//一棵树的长度的求法
//得到左边的长度,得到右边的长度
}
int result(TreeNode root){
if(root==null)
return 0;
//整个这个函数实际上是进行优化了的
//所以使用优化的思想也很总要
// 这里原本是用来计算数的深度的
//在计算深度的同时计算两边深度的和
int left1= result(root.left);
int right1= result(root.right);
maxum=Math.max(maxum,right1+left1);
return Math.max(left1,right1)+1;
}
}
二叉树的前序遍历
top:144
class Solution {
LinkedList<Integer>list=new LinkedList<>();
public List<Integer> preorderTraversal(TreeNode root) {
sum(root);
return list;
}
void sum(TreeNode root){
if(root==null){
return ;
} list.add(root.val);
sum(root.left);
sum(root.right);
// list.add(left.root).add(root.right);
}
}
top:114
二叉树转换为链表:
class Solution {
public void flatten(TreeNode root) {
//先序遍历是这样的,先递归遍历左边,再递归遍历右边
if(root==null)
return ;
TreeNode node=root.right;
root.right=root.left;
root.left=null;
TreeNode bt=root;
while(bt.right!=null){
bt=bt.right;
}
bt.right=node;
}
flatten(root.left);
flatten(root.right);
}
top:116题
116. 填充每个节点的下一个右侧节点指针
class Solution {
//Queue<Node>list=new Queue<>();
public Node connect(Node root) {
//写一个连接的函数
if(root==null)
return root;
connectNode(root.left,root.right);
return root;
}
void connectNode(Node n1,Node n2){
if(n1==null||n2==null)
return ;
n1.next=n2;
connectNode(n1.left,n1.right);
connectNode(n2.left,n2.right);
connectNode(n1.right,n2.left);
}
}
力扣第 341 题「 扁平化嵌套列表迭代器」
属于:树的习题
参考:n叉树的节点和遍历的问题
for (TreeNode t:root.children ){
traverse(root.children)
}
*/public class NestedIterator implements Iterator<Integer> {
private LinkedList<NestedInteger> list;
public NestedIterator(List<NestedInteger> nestedList) {
// 不直接用 nestedList 的引用,是因为不能确定它的底层实现
// 必须保证是 LinkedList,否则下面的 addFirst 会很低效
list = new LinkedList<>(nestedList);
}
public Integer next() {
// hasNext 方法保证了第一个元素一定是整数类型
return list.remove(0).getInteger();
}
public boolean hasNext() {
// 循环拆分列表元素,直到列表第一个元素是整数类型
while (!list.isEmpty() && !list.get(0).isInteger()) {
// 当列表开头第一个元素是列表类型时,进入循环
List<NestedInteger> first = list.remove(0).getList();
// 将第一个列表打平并按顺序添加到开头
for (int i = first.size() - 1; i >= 0; i--) {
list.addFirst(first.get(i));
}
}
return !list.isEmpty();
}
}
这里讲了一个关于设计迭代器的知识,迭代器支持惰性运算;
而这里实际上是被看作一个n叉树,通过next得到值,而通过hasnext来不断地将
一个列表里的值写到list里面。
但是由于我对于java的语法等还是不是特别的了解擅长,因此就会出现这样的问题。
最近的公共祖先
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null)
return null;
if(root==p||root==q){
return root;
}
TreeNode left= lowestCommonAncestor( root.left, p, q);
TreeNode right= lowestCommonAncestor( root.right, p, q);
if(left!=null&&right!=null)
return root;
if(left==null&&right==null)
return null;
return left==null?right:left;
//这个就是使用抽象的方法,得到一种类似于抽象结构。
}
完全二叉树的节点的求解方法:
class Solution {
public int countNodes(TreeNode root) {
//计算完全二茶树的方法对于计算完美二叉树和普通二叉树,就是把两者的方法结合起来
TreeNode l1=root,l2=root;
int h1=0,h2=0;
while(l1!=null){
l1=l1.left;
h1++;
}
while(l2!=null){
l2=l2.right;
h2++;
}
if(h1==h2){
int sum= (int)Math.pow(2,h1)-1;
return sum;
}
else{
return 1+countNodes(root.left)+countNodes(root.right);
}
}
}
使用哈希表和链表或者使用哈希链表来对lru策略的实现。
lru,这是缓存淘汰策略的一种实现;它是根据最近访问决定是否淘汰它的;还有一种是根据它的访问频率。
class LRUCache {
int capacity;
LinkedHashMap<Integer,Integer> ls=new LinkedHashMap<>();
public LRUCache(int capacity) {
this.capacity=capacity;
}
public int get(int key) {
if(!ls.containsKey(key)){
return -1;
}
//接下来就要把这个value去掉,使用一个自定义的函数来重新的把这个结果加进去
makeRecently(key);
return ls.get(key);
}
public void put(int key, int value) {
if(ls.containsKey(key)){
ls.put(key,value);
makeRecently(key);
return ;
//这里为什么要加return?是为了防止刚好为10个,导致下一步的操作
}
if(ls.size()>=this.capacity)
{
int oldestKey = ls.keySet().iterator().next();
//int oldkey=ls.keySet().iterator().next();
ls.remove(oldestKey);
}
ls.put(key,value);
}
private void makeRecently(int key){
int value= ls.get(key);
ls.remove(key);
ls.put(key,value);
}
}
class LFUCache {
HashMap<Integer,Integer>key_val;
HashMap<Integer,Integer>key_fre;
HashMap<Integer,LinkedHashSet<Integer>>fre_keys;
int minfre;
int cap;
public LFUCache(int capacity) {
this.cap=capacity;
this.minfre=0;
key_val=new HashMap<>();
key_fre=new HashMap<>();
fre_keys=new HashMap<>();
}
public int get(int key) {
if(!key_val.containsKey(key))
{
return -1;
}
//m每get一次就会增加fre,因此写一个函数来
incrFre(key);
return key_val.get(key);
}
public void put(int key, int value) {
if(this.cap==0)
return;
//如果有呢
if(key_val.containsKey(key)){
//把原来的去掉,再加上一次访问次数,要更新fre——keys结构,这种更新的操作可以写在函数中
key_val.put(key,value);
incrFre(key);
return;
}
//没有呢,看cap
if(this.cap<=key_val.size()){
//去掉次数最小的访问频率
remFre();//这个函数怎么实现呢?
}
//开始非特殊的操作
//key_val.put(key,val);
key_val.put(key,value);
key_fre.put(key,1);
//到这里就说明key是不存在的,也就是新的,但是有1个访问次数的有多少是不知道的
fre_keys.putIfAbsent(1,new LinkedHashSet<>());//这里使用putIfabsent的作用是区分1
//是否存在
fre_keys.get(1).add(key);//说明是存在的
this.minfre=1;
}
private void incrFre(int key){
int fre=key_fre.get(key);
key_fre.put(key,fre+1);
//把key从次数的表里删除
fre_keys.get(fre).remove(key);
fre_keys.putIfAbsent(fre+1,new LinkedHashSet<>());
fre_keys.get(fre+1).add(key);
//存在这种可能,如果这个被删除的表空了,那就应该删除
if(fre_keys.get(fre).isEmpty()){
fre_keys.remove(fre);
if(fre==this.minfre)
this.minfre++;
}
}
private void remFre(){
LinkedHashSet<Integer>result= fre_keys.get(this.minfre);
int del=result.iterator().next();
result.remove(del);
//看他会不会空
if(result.isEmpty()){
fre_keys.remove(this.minfre);
}
key_val.remove(del);
key_fre.remove(del);
}
//这里我们要维护一个最小的频率的表,
//而这个最小的频率的表应该有对应的key,
//我们要建的表应该是key-value和key-fre,fre-key的表
//通过key找到value,通过key找到fre,反之查找
//数据类型确定了,后面还要设计函数来进行实现
}
/**
* Your LFUCache object will be instantiated and called as such:
* LFUCache obj = new LFUCache(capacity);
* int param_1 = obj.get(key);
* obj.put(key,value);
*/
实现trie树的api;
首先是给了接口,然后要实现这个接口。
208. 实现 Trie (前缀树)
class Trie {
//创建字典树
private Trie []child;
private boolean isEnd;
public Trie() {
child=new Trie[26];
isEnd=false;
}
public void insert(String word) {
//遍历整个单词,放到树中
Trie node=this;
for(int i=0;i<word.length();i++){
int index=word.charAt(i)-'a';
if(node.child[index]==null){
node.child[index]=new Trie();
}
node= node.child[index];
}
node.isEnd=true;
}
public boolean search(String word) {
Trie node= searchPrefix(word);
return node!=null&&node.isEnd ;
//在这里我犯了一个错误,就是应该先看ndoe!=null,不能把两个弄反了
}
public boolean startsWith(String prefix) {
return searchPrefix(prefix)!=null;
}
public Trie searchPrefix(String prefix){
//如何搜索它的前缀?
Trie node=this;
for(int i=0;i<prefix.length();i++){
int index=prefix.charAt(i)-'a';
if(node.child[index]==null){
return null;
}
node=node.child[index];
}
return node;
}
}
首先要明白split方法的参数含义:
split
public String[] split(String regex)根据给定的正则表达式的匹配来拆分此字符串。
然后就要明确正则表达式的含义了:
\\s表示 空格,回车,换行等空白符,
+号表示一个或多个的意思,所以.
648. 单词替换
class Solution {
public String replaceWords(List<String> dictionary, String sentence) {
//
TrieNode rot=new TrieNode();
for(String s:dictionary){
TrieNode node=rot;
for(char t:s.toCharArray()){
if(node.children[t-'a']==null){
node.children[t-'a']=new TrieNode();
}
node=node.children[t-'a'];
}
node.root=s;
}
//通过上面的步骤就可以得到字典树
//然后要开始的就是用切割的方法来得到sentence,可以通过正则表达式来切割
StringBuffer res=new StringBuffer();
for(String s:sentence.split("\\s+"))
{
if(res.length()>0){
res.append(" ");
}
TrieNode node1=rot;
for(char t:s.toCharArray()){
if(node1.children[t-'a']==null||node1.root!=null){
break;
}
node1=node1.children[t-'a'];
}
res.append(node1.root!=null?node1.root:s);
//在这个过程中,要会看切割的字符串是否由字典树的值,有的话加入到动态的string里
}
return res.toString();
}
//单词替换,首先是把单词放到字典树里面去
//这里的字典树无非就是两种种状态,节点存不存在,节点有没有值,节点的代表字母是由数字表示的
//设计一种数据结构
class TrieNode{
TrieNode []children;
String root;
TrieNode(){
children=new TrieNode[26];
}
}
}
1.纪录题目
2.学习数据结构的使用方法
对于hashmap的复合使用:
map映射,然后再进行映射
class FreqStack {
HashMap<Integer,Integer> map;
HashMap<Integer,Stack<Integer>> fre;
int maxfre;
public FreqStack() {
map=new HashMap<>();
fre=new HashMap<>();
maxfre=0;
}
public void push(int val) {
int ree= map.getOrDefault(val,0)+1;
map.put(val,ree);
fre.putIfAbsent(ree,new Stack<>());
fre.get(ree).push(val);
maxfre=Math.max(ree,maxfre);
}
public int pop() {
Stack<Integer>all= fre.get(maxfre);
int result=all.pop();
map.put(result, map.get(result)-1);
if(all.isEmpty()){
maxfre--;
}
return result;
}
}
###################这里使用了hashmap和stack;
使用了hashmap的getordefault和putIfabsent等方法。
295. 数据流的中位数(困难)
对于数据流来说,因为处理的数据的量特别大,这道题就是求中位数,如果数据的量比较小的话,那么可以使用排序的方法,但是这里的数据的量特别的大,因此就应该使用其他的方法。
class MedianFinder {
//这里采用的是优先级队列的方法来写的,
// 通过使用两个优先级的最小和最大的队列
private PriorityQueue<Integer>large;//小顶堆
private PriorityQueue<Integer>small;//大顶堆
public MedianFinder() {
large =new PriorityQueue<>();
small=new PriorityQueue<>((a,b)->{return b-a;});//这里弄一个函数式编程
}
public void addNum(int num) {
//怎么进行添加呢?
//目的是维持两个只能相差1
if(large.size()>=small.size()){
large.offer(num);
small.offer(large.poll());
}
else{
small.offer(num);
large.offer(small.poll());
}
}
public double findMedian() {
if(small.size()>large.size()){
return small.peek();
}
else{
return (large.peek()+small.peek())/2.0;
}
}
}}``
```typescript
```typescript
在这里插入代码片
23. 合并K个升序链表
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
//在java中的数据结构中,有着这么的数据结构,优先队列
//使用优先队列可以把三个链表放进去
//实际上两个链表的合并也可以使用最小堆
//数组是length
if(lists.length==0){
return null;
}
ListNode firstNode=new ListNode(-1);
ListNode node=firstNode;
PriorityQueuels=new PriorityQueue<>(lists.length,(a,b)->(a.val-b.val));
for(ListNode k:lists){
if(k!=null){
ls.add(k);
}
}
while(!ls.isEmpty()){
ListNode k=ls.poll();
node.next=k;
if(k.next!=null){
ls.add(k.next);
}
node=node.next;
}
return firstNode.next;
}
}
这里使用优先队列的函数
160. 相交链表
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
//快捷的方法
//将两个链表在逻辑上连接到一起
ListNode p=headB;
ListNode q=headA;
while(p!=q){
if(p!=null){
p=p.next;
}
else{p=headA;}
if(q!=null){
q=q.next;
}else{q=headB;}
}
return p;
}
}
19. 删除链表的倒数第 N 个结点
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
//使用两个指针的方式
ListNode dumy=new ListNode(-1);
dumy.next=head;
ListNode de= find(dumy,n+1);
de.next=de.next.next;
return dumy.next;
}
ListNode find(ListNode p,int k){
//找前一个节点
ListNode dumy1=p;
for(int i=0;i<k;i++){
dumy1=dumy1.next;
}
ListNode h1=p;
while(dumy1!=null){
dumy1=dumy1.next;
h1=h1.next;
}
return h1;
}
}
142. 环形链表 II
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast=head;
ListNode slow=head;
// ListNode end=head;
while(fast!=null&&fast.next!=null){
fast=fast.next.next;
slow=slow.next;
if(fast==slow){
break;
}
}
if(fast==null||fast.next==null){
return null;
}
slow=head;
while(slow!=fast){
slow=slow.next;
fast=fast.next;
}
return slow;
}
}