单词矩阵(创建由字母组成的面积最大的矩形)

单词矩阵

给定一份单词的清单,设计一个算法,创建由字母组成的面积最大的矩形,其中每一行组成一个单词(自左向右),每一列也组成一个单词(自上而下)。不要求这些单词在清单里连续出现,但要求所有行等长,所有列等高。
如果有多个面积最大的矩形,输出任意一个均可。一个单词可以重复使用。
示例 1:
输入: [“this”, “real”, “hard”, “trh”, “hea”, “iar”, “sld”]
输出:
[
“this”,
“real”,
“hard”
]

比较复杂,所以还是看注释吧.主要就是构造前缀树,然后DFS+回溯,同时利用前缀树来判断是否符合要求

public class Main17_25 {
    public static void main(String[] args) {

    }

    static Trie root;
    static int maxArea,maxLength;
    static List<String> ans;
    public static String[] maxRectangle(String[] words) {
        root = new Trie();
        Map<Integer, Set<String>> map = new HashMap<>();//用map来存放长度len,以及长度为len的所有单词的集合set
        maxArea = 0;
        maxLength = 0;
        ans = new ArrayList<>();

        //构造前缀树
        for (String str : words) {
            Trie node = root;
            for (int i = 0; i < str.length(); i++) {
                if (node.chrilren[str.charAt(i) - 'a'] == null) {
                    node.chrilren[str.charAt(i) - 'a'] = new Trie();
                }
                node = node.chrilren[str.charAt(i) - 'a'];
            }
            node.isLeaf = true;//将单词结尾处的isleaf置true 表示一个单词的结尾
        }

        //将每个单词放到map中
        for (String str : words) {
            maxLength = Math.max(str.length(), maxLength);
            Set<String> set = map.getOrDefault(str.length(), new HashSet<>());
            set.add(str);
            map.put(str.length(), set);
        }

        //进行DFS
        List<String> path = new ArrayList<>();
        for (int len:map.keySet()){
            path.clear();//将前一次的结果清空
            //回溯需要的参数是:相同长度单词的集合,存放路径的列表,当前单词的长度
            DFS(map.get(len),path,len);
        }

        return ans.toArray(new String[ans.size()]);
    }

    public static void DFS(Set<String> set,List<String> path,int wordLen){
        //剪枝:set里的情况不可能得到最优解,提前过滤掉不考虑
        if (wordLen*maxLength<=maxArea) return;
        //剪枝:如果path矩阵的高度已经超过清单中最长单词长度,结束
        if (path.size()>maxLength) return;

        for (String str:set){
            path.add(str);

            //valid[0]表示是否有字母不在字典树中
            //valid[1]表示是否所有的列都构成了清单里的单词
            boolean[] valid = isValid(path);

            //都在清单
            if (valid[0]){
                int area = path.size()*path.get(0).length();
                //都是末尾的字符了 可以结束本次
                if (valid[1]&&(area>maxArea)){
                    maxArea =area;
                    ans = new ArrayList<>(path);
                }
                DFS(set,path,wordLen);
            }

            //回溯
            path.remove(path.size()-1);
        }

    }

    /**
     *
     */
    /* 判断一个矩阵是否每一列形成的单词都在清单里
     * 存在两种情况:1.有的列中的字母不在字典树中,即这一列不可能构成单词,整个矩阵不合要求
     * 2.每列的所有字母都在字典树中但有的结尾不是leaf,也就是有的列目前还不是个单词
     * 所以需要一个boolean数组res[]来存放结果:
     * res[0]表示是否有字母不在字典树中,true:都在,false:有不在的
     * res[1]表示是否所有的列都构成了清单里的单词
     */
    public static boolean[] isValid(List<String> path){
        boolean allLeaf = true;
        for (int i=0;i<path.get(0).length();i++){
            //按列来看单词是否在字典树
            Trie node =root;
            for (int j=0;j<path.size();j++){
                int ch = path.get(j).charAt(i)-'a';
                if (node.chrilren[ch]==null) return new boolean[]{false,false};
                node = node.chrilren[ch];
            }
            if (!node.isLeaf) allLeaf=false;
        }

        return new boolean[]{true,allLeaf};
    }
}

//构造前缀树
class Trie {
    Trie[] chrilren;
    boolean isLeaf;//是否是叶子结点 单词的结尾

    public Trie() {
        chrilren = new Trie[26];
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值