zoukankan      html  css  js  c++  java
  • 左神算法第七节课:前缀树,贪心策略(字符串数组拼接,切割金条,代价利润),数据流中位数,举办宣讲会场数最多

    1.何为前缀树?TrieTree

    在计算机科学中,trie,又称前缀树或字典树,是一种有序树,用于保存关联数组,其中的键通常是字符串。与二叉查找树不同,键不是直接保存在节点中,而是由节点在树中的位置决定。一个节点的所有子孙都有相同的前缀,也就是这个节点对应的字符串,而根节点对应空字符串。一般情况下,不是所有的节点都有对应的值,只有叶子节点和部分内部节点所对应的键才有相关的值。

    trie中的键通常是字符串,但也可以是其它的结构。

    举例:

    当有四个字符串时:“abc”,”bce”,”abd”,”bef”.下图中:边上的是字符,树内的数字是以当前字符结尾的字符串有多少个。比如,加入”bef”后,f后面的数字就由0-->1,再加入”be”后,‘e’处的数值就由0变成了1;求:有多少个字符串以“be”做为前缀?直接找到“be”处的'e'的数字即可。

      1 /*
      2  * 前缀树,查看两个字符串数组内元素;
      3  */
      4 public class Code_01_TrieTree {
      5 
      6     public static class TrieNode {
      7         public int path;//经过该节点的次数
      8         public int end;//以该节点为结尾的字符串的个数;
      9         public TrieNode[] nexts;
     10         public TrieNode() {
     11             path = 0;
     12             end = 0;
     13             nexts = new TrieNode[26];//26个字母对应0--25下标
     14         }
     15     }
     16     
     17     public static class Trie {
     18         private TrieNode root;//根节点
     19         public Trie() {
     20             root = new TrieNode();
     21         }
     22         
     23         public void insert(String word) {
     24             if (word == null) {
     25                 return;
     26             }
     27             char[] chs = word.toCharArray();
     28             TrieNode node = root;
     29             int index = 0;
     30             for (int i = 0; i < chs.length; i++) {
     31                 index = chs[i]-'a';//将字母对应成下标
     32                 if (node.nexts[index] == null) {
     33                     node.nexts[index] = new TrieNode();
     34                 }
     35                 node = node.nexts[index];
     36                 node.path++;
     37             }
     38             node.end++;    
     39         }
     40         
     41         public void delete(String word) {
     42             if (search(word) != 0) {
     43                 char[] chs = word.toCharArray();
     44                 int index = 0;
     45                 TrieNode node = root;
     46                 for (int i = 0; i < chs.length; i++) {
     47                     index = chs[i] - 'a';
     48                     if (--node.nexts[index].path == 0) {
     49                         node.nexts[index] = null;
     50                         return;
     51                     }
     52                     node = node.nexts[index];
     53                 }
     54                 node.end--;
     55             }
     56         }
     57         
     58         public int search(String word) {
     59             if (word == null) {
     60                 return 0;
     61             }
     62             char[] chs = word.toCharArray();
     63             int index = 0;
     64             TrieNode node = root;
     65             for (int i = 0; i < chs.length; i++) {
     66                 index = chs[i] - 'a';
     67                 if (node.nexts[index] == null) {
     68                     return 0;
     69                 }
     70                 node = node.nexts[index];
     71             }
     72             return node.end;            
     73         }
     74     }
     75     
     76     
     77     
     78     public static void main(String[] args) {
     79         test();
     80 
     81     }
     82 
     83 
     84 
     85     private static void test() {
     86         Trie trie = new Trie();
     87         System.out.println(trie.search("zuo"));
     88         trie.insert("zuo");
     89         System.out.println(trie.search("zuo"));
     90         trie.delete("zuo");
     91         System.out.println(trie.search("zuo"));
     92         trie.insert("zuo");
     93         trie.insert("zuo");
     94         trie.delete("zuo");
     95         System.out.println(trie.search("zuo"));
     96         trie.delete("zuo");
     97         System.out.println(trie.search("zuo"));
     98         trie.insert("zuoa");
     99         trie.insert("zuoac");
    100         trie.insert("zuoab");
    101         trie.insert("zuoad");
    102         trie.delete("zuoa");
    103         System.out.println(trie.search("zuoa"));
    104         System.out.println(trie.search("zuoac"));
    105         System.out.println(trie.search("zuoab"));
    106         System.out.println(trie.search("zuoad"));
    107     }
    108 
    109 }

    2.字符串数组拼接—贪心策略

    (对数器小样本测,不纠结证明过程)

    字符串数组,将各字符串拼接,使得最低词典顺序。如:“ab”,“cd”,“ef”,拼接成“abcdef”最小,其他方式都比它大。到这里可能想到排序,再拼接,有一种情况是,“b”和“ba”拼接,排序后是“b”,“ba”,拼接后是“b ba”,但是按照“b ab”拼接的话,更小,故刚才对字符串按照字典的排序进行拼接是不对的。所以排序策略需要改变一下。

    对str1,str2排序:

    原先的拼接策略是:str1<=str2,str1放前,否则str2放前;

    改进后拼接策略是:str1+str2<=str2+str1,str1放前,否则str2放前;

    证明过程:

    证明排序的传递性:a.b表示a后拼接b,拼接后可以看成a在高位,b在低位,a.b表示a是向左移动了b的长度个位数再加上b。a.b可以看成是k进制的拼接,即a*Kb长度+b,令

    Kb长度=m(b),故a.b=a*m(b)+b;

     

                                    

    /*
     * 给定一个字符串类型的数组strs,找到一种拼接方式,使得把所
     * 有字 符串拼起来之后形成的字符串具有最低的字典序。
     */
    public class Code_05_LowestLexicography {
    
        public static class MyComparator implements Comparator<String>{
            @Override
            public int compare(String o1, String o2) {
                return (o1+o2).compareTo(o2+o1);
            }        
        }
        public static String lowestString(String[] strs) {
            if (strs == null || strs.length < 1) {
                return null;
            }
            Arrays.sort(strs, new MyComparator());
            String res = "";
            for (int i = 0; i < strs.length; i++) {
                res = res + strs[i] + "-";
            }
            return res;
        }
        
        private static void test() {
            String[] strs1 = { "jibw", "ji", "jp", "bw", "jibw" };
            System.out.println(lowestString(strs1));
    
            String[] strs2 = { "ba", "b" };
            System.out.println(lowestString(strs2));
            
        }
        public static void main(String[] args) {
            test();
        }
    
    }

    在这里:

    3. 切割金条问题—贪心策略

    一块金条切成两半,是需要花费和长度数值一样的铜板的。比如长度为20的 金条,不管切成长度多大的两半,都要花费20个铜板。一群人想整分整块金 条,怎么分最省铜板?例如,给定数组{10,20,30},代表一共三个人,整块金条长度为10+20+30=60. 金条要分成10,20,30三个部分。 如果先把长度60的金条分成10和50,花费60 再把长度50的金条分成20和30,花费50 一共花费110铜板。但是如果, 先把长度60的金条分成30和30,花费60 再把长度30金条分成10和20,花费30 一共花费90铜板。输入一个数组,返回分割的最小代价。

    思路:通过定义不同的比较器,来实现不同的堆。该题利用最小堆,每次从堆里找出最小的两个数,合并之后再插入堆中,依次循环,直至堆中只剩下一个数停止。其实本质是哈夫曼问题。

     

     1 public static class MinHeapComparator implements Comparator<Integer>{
     2         @Override
     3         public int compare(Integer o1, Integer o2) {
     4             // TODO Auto-generated method stub
     5             return o1.compareTo(o2);//负数第一个前
     6         }        
     7     }
     8     
     9     public static int lessMoney(int[] arr) {
    10         int sum = 0;
    11         if (arr == null || arr .length <1) {
    12             return 0;
    13         }
    14         PriorityQueue<Integer> pq = new PriorityQueue<>(new MinHeapComparator());
    15         for (int i = 0; i < arr.length; i++) {
    16             pq.add(arr[i]);
    17         }
    18         int temp = 0;
    19         while (pq.size() > 1) {
    20             temp = pq.poll() + pq.poll();
    21             sum += temp;
    22             pq.add(temp);
    23         }
    24         
    25         return sum;
    26     }

    4. 代价利润问题—贪心策略

    给定两个数组,Costs[…….]和Profits[…....],数组大小相等,一次只能做一个项目,一共最多做k个项目,初始资金W,求最大收益(钱剩下多少)。

    输入:参数1,正数数组costs;参数2,正数数组profits;参数3,正数k;参数4,正数m。costs[i]表示第i个项目的花费,profits[i]表示第i个项目在扣除花费之后还能挣到的钱(利润),k表示你不能并行、只能串行的最多做k个项目,m表示你初始的资金。说明:你每做完一个项目,马上获得的收益,可以支持你去做下一个项目。

    输出:你最后获得的最大钱数。

    思路:运用小根堆+大根堆,把所有项目按照cost放入小根堆中,然后从小根堆中取出所有比此时的总钱小的项目放入按照profit排序的大根堆,意思是利用现在的钱将能做的项目都放入大根堆,然后从大根堆中每次取出一个栈顶项目(利润最大项目),然后再将总钱数增加,再去小根堆里找出所有比当前总钱数要少的项目,依次循环,直至大根堆里没有项目。

     1 /*
     2  给定两个数组,Costs[…….]和Profits[…....],数组大小相等,一次只能做一个项目,
     3   一共最多做k个项目,初始资金W,求最大收益(钱剩下多少)。
     4 输入:参数1,正数数组costs 参数2,正数数组profits 参数3,正数k 参数4,正数m。
     5     costs[i]表示第i个项目的花费,profits[i]表示第i个项目在扣除花费之后还能挣到的钱(利润),
     6     k表示你不能并行、只能串行的最多做k个项目,m表示你初始的资金。
     7     说明:你每做完一个项目,马上获得的收益,可以支持你去做下一个项目。
     8 输出: 你最后获得的最大钱数。
     9 
    10  */
    11 public class Code_03_IPO {
    12 
    13     public static class Node{
    14         public int cost;
    15         public int profit;
    16         public Node(int c, int p){
    17             cost = c;
    18             profit = p;
    19         }
    20     }
    21     
    22     public static class MinHeapComparator implements Comparator<Node>{
    23         @Override
    24         public int compare(Node o1, Node o2) {
    25             return o1.cost-o2.cost;//负数第一个前
    26         }        
    27     }
    28     public static class MaxHeapComparator implements Comparator<Node>{
    29         @Override
    30         public int compare(Node o1, Node o2) {
    31             return o2.profit-o1.profit;//负数第一个前
    32         }        
    33     }
    34     public static int findMaximizedCapital(int k, int W, int[] Profits, int[] Capital) {        
    35         if (Profits == null || Capital == null || Profits.length < 1 || Capital.length < 1) {
    36             return W ;
    37         }
    38         Node[] nodes = new Node[Profits.length];
    39         for (int i = 0; i < Profits.length; i++) {
    40             nodes[i] = new Node(Profits[i], Capital[i]);
    41         }
    42         PriorityQueue<Node> minPQ = new PriorityQueue<>(new MinHeapComparator());
    43         PriorityQueue<Node> maxPQ = new PriorityQueue<>(new MaxHeapComparator());
    44         for (int i = 0; i < nodes.length; i++) {
    45             minPQ.add(nodes[i]);
    46         }
    47         int time = 0;
    48         while (time < k) {
    49             while(!minPQ.isEmpty() && minPQ.peek().cost < W) {
    50                 maxPQ.add(minPQ.poll());
    51             }
    52             if (maxPQ.isEmpty()) {
    53                 return W;
    54             }
    55             W+=maxPQ.poll().profit;
    56             time++;
    57         }
    58         return W;
    59     }    
    60     public static void main(String[] args) {
    61     }
    62 }

    自己做:带输入输出

     1 public class Code_03_IPO1 {
     2 
     3     public static class MyMinComparator implements Comparator<projest>{
     4 
     5         @Override
     6         public int compare(projest o1, projest o2) {
     7             return o1.cost-o2.cost;
     8         }
     9         
    10     }
    11     public static class MyMaxComparator implements Comparator<projest>{
    12 
    13         @Override
    14         public int compare(projest o1, projest o2) {
    15             return o2.profit-o1.profit;
    16         }
    17         
    18     }
    19     
    20     public static class projest {
    21         int cost;
    22         int profit;
    23         public projest(int c,int p) {
    24             this.cost = c;
    25             this.profit = p;
    26         }
    27     }
    28     
    29     public static void main(String[] args) {
    30         Scanner sc = new Scanner(System.in);
    31         String costStr = sc.nextLine();
    32 //        System.out.println("999");
    33         String profitStr = sc.nextLine();
    34 //        System.out.println("888");
    35         int k = sc.nextInt();
    36         int m = sc.nextInt();
    37         String[] costs = costStr.split(" ");
    38         String[] profits = profitStr.split(" ");
    39         int[] cost = new int[costs.length];
    40         int[] profit = new int[profits.length];
    41         projest[] ps = new projest[cost.length];
    42         for (int i = 0; i < profit.length; i++) {
    43             cost[i] = Integer.valueOf(costs[i]);
    44             profit[i] = Integer.valueOf(profits[i]);
    45             ps[i] = new projest(cost[i], profit[i]);
    46         }
    47         
    48         Queue<projest> minQueue = new PriorityQueue<projest>(new MyMinComparator());
    49         Queue<projest> maxQueue = new PriorityQueue<projest>(new MyMaxComparator());
    50         for (int i = 0; i < ps.length; i++) {
    51             minQueue.add(ps[i]);
    52         }
    53         int k1 = 0;
    54         while (!minQueue.isEmpty() || !maxQueue.isEmpty()) {
    55             while (!minQueue.isEmpty() && minQueue.peek().cost<=m) {
    56                 maxQueue.add(minQueue.poll());
    57             }
    58             if (k1<k) {
    59                 m += maxQueue.poll().profit;
    60                 k1++;
    61             }else {
    62                 break;
    63             }
    64         }
    65         System.out.println(m);
    66 
    67     }
    68 
    69 }

    5. 求数据流中的中位数

    如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。

    思路:一个大根堆,一个小根堆。小根堆里放的是较大的数,大根堆里放的是较小的数,然后每次进来的数与小根堆的堆顶相比较,再记一个变量记录当前进来的数是第几个,如果是序号是奇数。

     1 public class Code_04_MadianQuick {
     2 
     3     public static class MyMinComparator implements Comparator<Integer> {
     4         @Override
     5         public int compare(Integer o1, Integer o2) {
     6             return o1.compareTo(o2);
     7         }        
     8     }
     9     public static class MyMaxComparator implements Comparator<Integer> {
    10         @Override
    11         public int compare(Integer o1, Integer o2) {
    12             return o2.compareTo(o1);
    13         }    
    14     }
    15 
    16     public static void main(String[] args) {
    17         Scanner sc = new Scanner(System.in);
    18         String[] dataStr = sc.nextLine().split(" ");
    19         int[] datas = new int[dataStr.length];
    20         for (int i = 0; i < datas.length; i++) {
    21             datas[i] = Integer.valueOf(dataStr[i]);
    22         }
    23         
    24         Queue<Integer> minQueue = new PriorityQueue<Integer>(new MyMinComparator());
    25         Queue<Integer> maxQueue = new PriorityQueue<Integer>(new MyMaxComparator());
    26         
    27         for (int i = 0; i < datas.length; i++) {
    28             if (maxQueue.isEmpty()) {
    29                 maxQueue.add(datas[i]);
    30                 continue;
    31             }
    32             if (maxQueue.peek()>=datas[i]) {
    33                 maxQueue.add(datas[i]);
    34             }else {
    35                 if (minQueue.isEmpty()) {
    36                     minQueue.add(datas[i]);
    37                     continue;
    38                 }
    39                 if (minQueue.peek()<datas[i]) {
    40                     minQueue.add(datas[i]);
    41                 }else {
    42                     maxQueue.add(datas[i]);
    43                 }
    44             }
    45             //调整堆的大小
    46             if (maxQueue.size() == minQueue.size()+2) {
    47                 minQueue.add(maxQueue.poll());
    48             }
    49             if (maxQueue.size() == minQueue.size()-2) {
    50                 maxQueue.add(minQueue.poll());
    51             }        
    52         }//endfor
    53         //取中位数
    54         if ((datas.length&1)==0) {//偶数
    55             System.out.printf("%.6f",(maxQueue.peek()+minQueue.peek())/2.0);
    56         }else {
    57             System.out.println(maxQueue.size()>minQueue.size()?maxQueue.peek():minQueue.peek());
    58         }
    59     }
    60 }

    另:保留小数点后几位的三种写法:

    6. 求举办宣讲会场最多—贪心策略

    一些项目要占用一个会议室宣讲,会议室不能同时容纳两个项目的宣讲。 给你每一个项目开始的时间和结束的时间(给你一个数组,里面 是一个个具体的项目),你来安排宣讲的日程,要求会议室进行 的宣讲的场次最多。返回这个最多的宣讲场次。

    其中一种: 按照开始时间最早,错!按照每个持续的时间长短,也不行。

    正确思路:按照结束时间的早晚。找出最早结束的项目,然后过滤掉因该项目而不能举办的项目,依次循环。

     1 public class Code_06_BestArrange1 {
     2     
     3     public static class Program {
     4         int start;
     5         int end;
     6         public Program(int start, int end) {
     7             this.start = start;
     8             this.end = end;
     9         }
    10     }
    11     
    12     public static class MyComparator implements Comparator<Program> {
    13         @Override
    14         public int compare(Program o1, Program o2) {
    15             return o1.end-o2.end;//小根堆
    16         }        
    17     }
    18     //左神写
    19     public static int bestArrange(Program[] programs,int cur) {
    20         Arrays.sort(programs, new MyComparator());
    21         int count = 0;
    22         for (int i = 0; i < programs.length; i++) {
    23             if (cur <= programs[i].start) {
    24                 cur = programs[i].end;
    25                 System.out.println(programs[i].start+"---"+programs[i].end);
    26             }            
    27         }
    28         return 0;
    29     }
    30     
    31     public static void main(String[] args) {
    32         Scanner sc = new Scanner(System.in);
    33         String[] startStr = sc.nextLine().split(" ");
    34         String[] endStr = sc.nextLine().split(" ");
    35         int[] start = new int[startStr.length];
    36         int[] end = new int[endStr.length];
    37         Program[] programs = new Program[end.length];
    38         for (int i = 0; i < end.length; i++) {
    39             start[i] = Integer.valueOf(startStr[i]);
    40             end[i] = Integer.valueOf(endStr[i]);
    41             programs[i] = new Program(start[i], end[i]);
    42         }
    43         Queue<Program> queue = new PriorityQueue<Program>(new MyComparator());
    44         for (int i = 0; i < programs.length; i++) {
    45             queue.add(programs[i]);
    46         }
    47         while (!queue.isEmpty()) {
    48             Program pTemp = queue.poll();
    49 //            System.out.println(pTemp.start+"--"+pTemp.end);
    50             while (!queue.isEmpty() && queue.peek().start<pTemp.end) {
    51                 queue.poll();
    52             }
    53         }
    54         //法2
    55         bestArrange(programs,0);
    56     }
    57 }

    结果:

  • 相关阅读:
    thinkphp 事物回滚
    文字超出部分以省略号隐藏
    js倒计时
    js 日期转为时间戳
    jquery 获取url地址参数
    spreadjs 自定义菜单事件
    spreadjs 点击事件
    spreadjs 自定义上传文件单元格
    spreadjs 小记
    Json数组排序
  • 原文地址:https://www.cnblogs.com/gjmhome/p/11354034.html
Copyright © 2011-2022 走看看