数据结构与算法(java版本)leetcode刷题第一篇

二叉树刷题

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

}
  1. LFU 缓存
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;
    }
}

你可能感兴趣的:(算法,java,数据结构)