左程云算法 day8 前缀树和贪心算法

  • Post author:
  • Post category:其他


前缀树 :建立好前缀树后可以把下面的题目快速地解决,便于实现前缀查找

题目:一个字符串类型的数组arr1,另一个字符串类型的数组arr2.arr2中有哪些字符,是arr1中出现的,请打印。arr2中有哪些字符,是作为arr1中某些字符串前缀出现的?请打印。arr2中有哪些字符是arr1中某个字符串前缀出现的?请打印arr2中出现次数最多的前缀。

public class TrieNode {
    public static class TrieNode{
        public int pass;//表示通过该节点的次数
        public int end;//表示以该节点为终点的次数
        public TrieNode[] next;//表示下一节点的情况
        public void TrieNode(){
            pass = 0;
            end =0;
            next = new TrieNode[26];//表示后续可以有26个字母
        }
    }
    public static class Trie{
        private TrieNode root;
        public Trie(){
            root = new TrieNode();//默认根节点为只有后续的空节点
        }
        /*某个字符串出现的次数*/
        public int insert(String word){//插入一个字符串
            if(word == null){
                return 0;
            }
            char[] chs = word.toCharArray();//用array把word装起来
            TrieNode node = root;
            int index = 0;
            for (int i = 0; i < chs.length; i++) {
                index = chs[i]-'a';
                if(node.next[index]==null){
                    return 0;//有,不做任何动作
                }
                node = node.next[index];
            }
            return node.end;
        }
        /*判断是否含有某一个字符串的次数*/
        public int search(String word){
            if(word == null){
                return 0;
            }
            char[] chs = word.toCharArray();
            TrieNode node = root;
            int index = 0;
            for (int i = 0; i < chs.length; i++) {
                index = chs[i]-'a';
                if(node.next[index]==null){
                    return 0
                }
                node = node.next[index];
                return node.end;
            }
            return 0;
        }
       /*查找有多少个字符串是以某个字符串为前缀的*/
       public int search1(String word){
           if(word == null){
               return 0;
           }
           char[] chs = word.toCharArray();
           TrieNode node = root;
           int index = 0;
           for (int i = 0; i < chs.length; i++) {
               index = chs[i]-'a';
               if(node.next[index]==null){
                   return 0;
               }
               node = node.next[index];
               return node.pass;
           }
           return 0;
       }
       public void delete(String word){
           if(word == null){
               return ;
           }
           char[] chs = word.toCharArray();
           TrieNode node = root;
           int index = 0;
           for (int i = 0; i < chs.length; i++) {
               index = chs[i]-'a';
               if(node.next[index]==null){
                   return ;
               }
               else {
                   node.pass--;
                   if(node.pass==0) {
                       node.next=null;
                       return;
                   }
                   node = node.next[index];
               }
           }
           node.end--;
           return;
       }
       }
    }
}

贪心算法:在某一个标准下,优先考虑最满足标准的样本,最后考虑最不满足标准的样本,最终得到一个答案的算法,称为贪心算法。可以理解为先考虑局部最优再考虑全局最优。

套路:

题目一:


贪心策略:哪一个会议结束时间早就安排哪一个会议。

package greedyAl;

import java.util.Arrays;
import java.util.Comparator;

/**
 * @author 咕噜大飞侠
 * @version 1.0
 * Create by 24/2/2022 下午3:49
 */


public class BestArrange {
    public static class program{
        int star;
        int end;
        public void program(int star,int end){
            this.star=star;
            this.end=end;
        }
    }
    public static class ProgramComparator implements Comparator<program>{
        public int compare(program o1,program o2){
            return o1.end-o2.end;
        }
    }
    public static int bestArrange(program[] programs,int timePoint){
        Arrays.sort(programs,new ProgramComparator());
        int count=0;//记录能够满足的会议数量
        for (int i = 0; i < programs.length; i++) {
            if(timePoint<programs[i].end){
                count++;
                timePoint=programs[i].end;
            }
        }
        return count;
    }

}

贪心算法在笔试中的套路:

实现一个不依靠贪心策略的解法x,可以用最暴力的尝试;脑补出贪心策略A、贪心策略B、贪心策略C;用解法x和对数器,去验证每一个贪心策略,用实验的方式得知哪一个贪心策略正确,不去纠结贪心策略的证明。

字典序:哪一个单词在字典里面排前面就谁排前面。不同长度的字符串字典序处理:将短的后面补0使其等于长的。

拼接技巧:A B=A*K^B+B,其中K是该单个字符的进制

贪心策略在实现时的技巧:根据某标准建立一个比较器来排序;根据某标准建立一个比较器来组成堆

题目二

算法策略:采用哈夫曼树算法

public class LessMoneySplitGold {
    public static int lessMoneySplitGold(int[] arr){
        PriorityQueue<Integer> priorityQueue = new PriorityQueue<Integer>();
        for (int i = 0; i < arr.length; i++) {
            priorityQueue.add(arr[i]);
        }
        int sum = 0;
        int cur = 0;
        while (priorityQueue.size()>1){
            cur = priorityQueue.poll()+priorityQueue.poll();
            priorityQueue.add(cur);
            sum+=cur;
        }
        return sum;
    }
}

题目三:

策略:每次选择已有资金能够支持的利润最大的项目

一个小根堆,依靠花费排队;一个大根堆,能够满足花费的项目进堆,依靠利润最大存。

import java.util.Comparator;
import java.util.PriorityQueue;

/**
 * @author 咕噜大飞侠
 * @version 1.0
 * Create by 25/2/2022 上午9:40
 */


public class MostProfits {
    public static class Node{
        int c;
        int p;
        public Node(int c,int p){
            this.c=c;
            this.p=p;
        }
    }
    public static  MinCostComparator implements Comparator<Node> {
        @Override
        public int compare(Node O1, Node O2){
            return O1.c-O2.c;
        }
    }
    public static class MaxProfitComparator implements Comparator<Node> {
        @Override
        public int compare(Node O1, Node O2) {
            return O2.p - O1.p;
        }
    }
    public static class int mostProfits(int[] costs,int[] profits,int k,int m){
        PriorityQueue<Node> minCost=new PriorityQueue<Node>(new MinCostComparator());
        PriorityQueue<Node> maxPrifit=new PriorityQueue<>(new MaxProfitComparator());
            for (int i = 0; i < costs.length; i++) {
                minCost.add(new Node(costs[i],profits[i]));
            }
            for (int i = 0; i < k; i++) {
                while (!minCost.isEmpty()&&minCost.peek().p<=m){
                    maxPrifit.add(minCost.poll());
                }
                //跳出语句,没办法找到满足m的项目了
                if(maxPrifit.isEmpty()){
                    return m;
                }
                m+=maxPrifit.poll().p;
            }
            return m;
    }
}

题目四:在一个数据流中随时找到他的中位数。

策略:准备一个大根堆和小根堆;cur<=大根堆.peek?入大根堆:入小根堆;比较大根堆和小根堆的size,两差>=二,平衡调整

题目5:N皇后问题

public class NQueens {
    public static int nQueens(int n){//返回值为可以找到的摆法
        if(n<1){
            return 0;
        }
        int[] record = new int[n];
        return process(0,record,n);
    }
    public static int process(int i,int[] record,int n){ //i代表初始行数,n代表最多有多少行
        if(i==n){
            return 1;
        }
        int res = 0;
        for (int j = 0; j < n; j++) {
            if(isValid(record,i,j)){
                record[i]=j;
                res+=process(i+1,record,n);
            }
        }
        return res;
    }
    public static boolean isValid(int[] record,int i,int j){
        for(int k=0;k<i;k++){//这里遍历的是之前i行的情况
            if(j==record[k]||Math.abs(record[k]-j)==Math.abs(i-k)){//列一致或者成45度都误
                return false;
            }
        }
        return true;
    }
}

优化思路,使用位运算代替原来的record数组。0代表可以插入的位置,1代表不可以拜访的位置



版权声明:本文为be_lxx1原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。