• 字符串----最短摘要生成(尺取法)


    题目:Alibaba笔试题,给定一段产品的英文描述,包含M个英文单词,每个英文单词以空格分隔,无其他标点符号;再给定N个英文单词关键字,请说明思路并编程实现方法。String extractSummary(String description,String[] key words)目标是找出此产品描述中包含N个关键字(每个关键词至少出现一次)的长度最短的子串,作为产品简介输出。(不限编程语言)20分。

    思路一:

    直接暴力解法,循环暴力破解,每次判断关键字是否全部包含,然后不断更新边界。

    思路二:

    先来看看这些序列(w为英文单词,q为关键字):

    w0,w1,w2,w3,q0,w4,w5,q1,w6,w7,w8,q0,w9,q1

    问题在于,一次性扫描确定边界这不太现实,肯定要多次扫描,不断更新边界,这里只说每个关键字必须要出现一次以上,并没有说要顺序出现。先第一次扫描,扫描到第一个关键字,从第一个位置w0处将扫描到q0处:

    w0,w1,w2,w3,q0,w4,w5,q1,w6,w7,w8,q0,w9,q1

    然后再从q0处开始扫描,直到出现第一个包含所有关键字的序列,并记录边界:

    w0,w1,w2,w3,q0,w4,w5,q1,w6,w7,w8,q0,w9,q1

    然后扫描的位置继续往后移动,移动到q1,这样包含的序列中就少了q0,那么就从q1开始扫描,这样就可以找到下一个包含所有关键字的序列,即从q1扫描到了q0处,这儿也要更新边界:

    w0,w1,w2,w3,q0,w4,w5,q1,w6,w7,w8,q0,w9,q1

    然后,在继续往后扫描,定位到下一个关键字q0,继续往后扫描,如此循环往后扫描,直至扫描完成,那么边界长度就是最小的了。

    代码:

    import java.util.Arrays;
    import java.util.HashMap;
    import java.util.Map;
    
    public class 最短摘要 {
    
        public static void main(String[] args) {
             solve1(new String[]{"a", "b", "c", "seed", "h", "e", "f", "c", "c", "seed", "e", "f", "seed", "c"}, 
                     new String[]{"c", "e"});
             solve2(new String[]{"a", "b", "c", "seed", "c", "e", "f", "c", "c", "seed", "e", "f", "seed", "c"}, 
                     new String[]{"c", "c", "e", "f"});
             solve2(new String[]{"a", "b", "a", "a", "b", "c", "d", "h", "e", "f", "f"}, new String[]{"b", "c", "d"});
        }
    
        // 暴力破解法
        public static void solve1(String[] w, String[] q) {
            int length = Integer.MAX_VALUE;
            int begin = -1;
            int end = -1;
            for (int i = 0; i < w.length; i++) {
                // 求以i开头包含所有关键字的序列
                for (int j = i+1; j < w.length; j++) {
                    // 如果全部关键字已经再seq中。
                    if (containsAll(q,w,i,j)) {
                        // 判断当前这个序列是不是较短的序列
                        // System.out.println(seq);
                        if (j-i+1<length) {
                            length = j-i+1;
                            begin = i;
                            end = j;
                        }
                        break;
                    }
                }
            }
            print(w,begin,end);
        }
        
        /**
         * 这种解法解决了keys关键字中有重复的现象
         * @param w
         * @param keys
         */
        public static void solve2(String[] w, String[] keys) {
            Arrays.sort(keys);
            // begin和end用于在找到更短的包含全部关键字的子数组时更新
            int begin = -1;
            int end = -1;
            
            int j = -1;  // 上一次囊括了所有关键字的右边界
            
            int minLen = Integer.MAX_VALUE;
            for (int i = 0; i < w.length; i++) {
                // 如果i位置是关键字,求以i开头包含所有关键字的序列
                String word1 = w[i];
                int index = Arrays.binarySearch(keys, word1);
                if (-1==index) {
                    continue;
                }else {  // i是一个关键字
                    // 如果已经全部找到
                    if (j<w.length&&j>=i&&containsAll(keys, w, i, j)) {
                        if (j-i+1<minLen) {  // 更新
                            minLen = j-i+1;
                            begin = i;
                            end = j;
                        }
                        continue;
                    }
                }
                
                if (j==-1) {
                    j = j+1;   // j值初始化
                }
                while(j<w.length){
                    String word2 = w[j];  // 文章单词
                    int index1 = Arrays.binarySearch(keys, word2);
                    if (-1==index1) {
                        j++;
                        continue;
                    }else {  // 找到关键字  这里应该是第一次扫描的包含所有关键字的  然后继续for循环不断更新边界
                        if (containsAll(keys, w, i, j)) { //全部到齐  
                            if (j - i + 1 < minLen) {// 更新
                                minLen = j - i + 1;
                                begin = i;
                                end = j;
                            }
                            break;
                        }else {
                            j++;
                        }
                    }
                }
            }
            print(w, begin, end);
        }
    
        private static boolean containsAll(String[] keywords, String[] w, int i, int j) {
            Map<String, Integer> map = new HashMap<>();
            for (int k = 0; k < keywords.length; k++) {
                String key = keywords[k];
                if (map.get(key)==null) {
                    map.put(key, 1);
                }else {
                    map.put(key, map.get(key)+1);
                }
            }
            
            Map<String, Integer> map2 = new HashMap<>();
            for (int k = i; k <= j; k++) {
                String key = w[k];
                if (map2.get(key)==null) {
                    map2.put(key, 1);
                }else {
                    map2.put(key, map2.get(key)+1);
                }
            }
            for(Map.Entry<String, Integer> e:map.entrySet()){
                if (map2.get(e.getKey())==null||map2.get(e.getKey())<e.getValue()) {
                    return false;
                }
            }
            return true;
        }
    
        private static void print(String[] w, int begin, int end) {
            System.out.println(begin+" "+end);
            for (int i = begin; i <=end; i++) {
                System.out.print(w[i]+" ");
            }
            System.out.println();
        }
    
        
    
    }

    结果:

      

  • 相关阅读:
    MySQL命令 导出 数据和结构
    Maven web 项目工程的建立
    Maven的配置以及Eclipse的设置
    项目管理工具Maven的安装
    centos7 安装 redis
    Java + 腾讯邮箱 SSL加密问题 重要通知
    centos7 上配置Javaweb---MySQL的安装与配置、乱码解决
    关于阿里云Centos服务器搭建Java网站不能访问的问题
    浏览器使用经验
    Linux常用命令大全
  • 原文地址:https://www.cnblogs.com/xiaoyh/p/10306633.html
Copyright © 2020-2023  润新知