【程序员面试金典】面试题 17.25 . 单词矩阵

这篇具有很好参考价值的文章主要介绍了【程序员面试金典】面试题 17.25 . 单词矩阵。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

题目描述

描述:给定一份单词的清单,设计一个算法,创建由字母组成的面积最大的矩形,其中每一行组成一个单词(自左向右),每一列也组成一个单词(自上而下)。不要求这些单词在清单里连续出现,但要求所有行等长,所有列等高。

如果有多个面积最大的矩形,输出任意一个均可。一个单词可以重复使用。

示例 1:

输入: ["this", "real", "hard", "trh", "hea", "iar", "sld"]
输出:
[
   "this",
   "real",
   "hard"
]

示例 2:

输入: ["aa"]
输出: ["aa","aa"]

说明:

words.length <= 1000
words[i].length <= 100
数据保证单词足够随机

解题思路

思路:最直观的想法是,字典树。首先利用单词清单建立字典树,并且将单词按照长度分组,再记录一下最大单词长度方便剪枝。由于所有行等长且所有列等高,所以必定是长度相同的单词才能一起构建单词矩阵,又需要求解面积最大的单词矩阵,故优先搜索长度最长的单词分组。在搜索某一分组时,首先将该单词加入,此时可以保证按照行该单词是在字典树中的,现在只需按照列判断单词是否在字典树中,并区分是作为字典树的前缀还是作为完整的单词在字典树中,再依据此来更新最大单词矩阵面积。

//字典树类
class Trie{
    public:
        //标记是否结束
        bool isEnd;
        //记录下一个节点
        Trie* next[26];
        //构造函数
        Trie(){
            isEnd=false;
            memset(next,0,sizeof(next));
        }
        void insert(string s)
        {
            Trie* cur=this;
            for(int i=0;i<s.size();i++)
            {
                if(!cur->next[s[i]-'a'])
                    cur->next[s[i]-'a']=new Trie();
                cur=cur->next[s[i]-'a'];
            }
            cur->isEnd=true;
        }
};
class Solution {
public:
    //字典树根节点
    Trie* root=new Trie();
    vector<string> res;
    vector<string> temp;
    vector<string> maxRectangle(vector<string>& words) {
        //单词长度 单词列表
        map<int,vector<string>> mp;
        int maxlen=0,maxarea=0,area=0;
        for(auto word:words)
        {
            //建立字典树
            root->insert(word);
            //收集结果
            mp[word.size()].push_back(word);
            //求最大长度
            maxlen=max(maxlen,(int)word.size());
        }
        //反向遍历 长度从大到小
        for(auto it=mp.rbegin();it!=mp.rend();it++)
        {
            //最长单词*宽度 不够 不用寻找
            if(maxlen*(it->first)<maxarea)
                break;
            temp.clear();
            area=0;
            dfs(it->second,maxarea,maxlen,area);
        }
        return res;
    }
    void dfs(vector<string>& words,int& maxarea,int& maxlen,int& area)
    {
        //最大极限退出
        if(words[0].size()*maxlen<=maxarea)
            return;
        vector<bool> ans;
        //按行加入
        for(int i=0;i<words.size();i++)
        {
            temp.push_back(words[i]);
            ans=isgood(temp);
            //可以继续往下加单词
            if(ans[0])
            {
                area=temp.size()*temp[0].size();
                //均是结束单词且较大面积
                if(ans[1]&&area>maxarea)
                {
                    maxarea=area;
                    res=temp;
                }
                //否则继续添加单词
                dfs(words,maxarea,maxlen,area);
            }
            //不能else 回溯
            temp.pop_back();
        }
    }
    vector<bool> isgood(vector<string>& tp)
    {
        Trie *cur;
        bool allend=true;
        int n=temp[0].size();
        //按列检查
        for(int i=0;i<n;i++)
        {
            cur=root;
            for(int j=0;j<tp.size();j++)
            {
                if(!cur->next[tp[j][i]-'a'])
                    return {false,false};
                cur=cur->next[tp[j][i]-'a'];
            }
            allend&=cur->isEnd;
        }
        return {true,allend}; //可以继续插入
    }
};

总结:按照列判断单词是否在字典树中,此时可以返回两个参数加以区分,一个参数是是否可以继续加入单词,另一个参数是是否全部单词均已经结束。在C++中,逆序遍历map是使用mp.rbegin()和mp.rend()。文章来源地址https://www.toymoban.com/news/detail-529741.html

到了这里,关于【程序员面试金典】面试题 17.25 . 单词矩阵的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【程序员面试金典】面试题 17.23. 最大黑方阵

    描述:给定一个方阵,其中每个单元(像素)非黑即白。设计一个算法,找出 4 条边皆为黑色像素的最大子方阵。 返回一个数组 [r, c, size] ,其中 r, c 分别代表子方阵左上角的行号和列号,size 是子方阵的边长。若有多个满足条件的子方阵,返回 r 最小的,若 r 相同,返回 c 最小

    2024年02月12日
    浏览(27)
  • 【程序员面试金典】面试题 17.14. 最小K个数

    描述:设计一个算法,找出数组中最小的k个数。以任意顺序返回这k个数均可。 示例: 提示: 0 = len(arr) = 100000 0 = k = min(100000, len(arr)) 思路:最直观的想法是,排序。 扩展:最大堆。最小的k个数,那么就可以维持一个大小为k的最大堆,先填充k个数到最大堆中,然后再依次遍

    2024年02月11日
    浏览(42)
  • 【程序员面试金典】面试题 17.19. 消失的两个数字

    描述:给定一个数组,包含从 1 到 N 所有的整数,但其中缺了两个数字。你能在 O(N) 时间内只用 O(1) 的空间找到它们吗? 以任意顺序返回这两个数字均可。 示例 1: 示例 2: 提示: nums.length = 30000 思路:最直观的想法是,位运算。消失的两个数字和只出现一次的两个元素,本质

    2024年02月12日
    浏览(33)
  • 【程序员面试金典】面试题 17.21. 直方图的水量

    描述:给定一个直方图(也称柱状图),假设有人从上面源源不断地倒水,最后直方图能存多少水量?直方图的宽度为 1。 上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的直方图,在这种情况下,可以接 6 个单位的水(蓝色部分表示水)。 感谢 Marcos 贡献此图。 示例: 思路:最直观的想

    2024年02月11日
    浏览(31)
  • 《程序员面试金典(第6版)面试题 16.10. 生存人数(前缀和思想)

    给定 N 个人的出生年份和死亡年份,第 i 个人的出生年份为 birth[i],死亡年份为 death[i],实现一个方法以计算生存人数最多的年份。 你可以假设所有人都出生于 1900 年至 2000 年(含 1900 和 2000 )之间。如果一个人在某一年的任意时期处于生存状态,那么他应该被纳入那一年的

    2024年02月02日
    浏览(35)
  • 《程序员面试金典(第6版)》 面试题 08.11. 硬币(动态规划,组合问题,C++)

    硬币。给定数量不限的硬币,币值为25分、10分、5分和1分,编写代码计算n分有几种表示法。(结果可能会很大,你需要将结果模上1000000007) 示例1: 输入: n = 5 输出:2 解释: 有两种方式可以凑成总金额: 5=5 5=1+1+1+1+1 示例2: 输入: n = 10 输出:4 解释: 有四种方式可以凑成总金额: 1

    2023年04月08日
    浏览(38)
  • 程序员的25大Tomcat面试问题及答案

    1.Tomcat的缺省端口是多少,怎么修改? 1)找到Tomcat目录下的conf文件夹 2)进入conf文件夹里面找到server.xml文件 3)打开server.xml文件 4)在server.xml文件里面找到下列信息 port=\\\"8080\\\"改成你想要的端口 2.tomcat 有哪几种Connector 运行模式(优化)? bio:传统的Java I/O操作,同步且阻塞IO。

    2024年02月02日
    浏览(47)
  • 一位大专学历的女程序员要求月薪25K,学历重要吗?来看看面试过程

    “请提供一份完整的简历,以便我审查。从您的简历中,我感觉您写得还不错。方便的话,您可以自我简单介绍一下吗?“ ”好的,我叫李娟,拥有大专学位,目前正在寻找一份Java开发架构师的工作岗位。“ ”您期望的月薪是多少呢?“ ”我的期望月薪是25K左右。“ ”月

    2023年04月16日
    浏览(39)
  • 程序员必会的英语单词汇总,学习速度可提高10倍,偷偷超越你身边的大聪明

    虽然说英语不好也能学编程,但学习速度却大大减慢,尤其是到后面你要查资料或者上Github等英文网站的时候,浏览器自带的翻译还会出错。 所以我专门花了几天的时间,结合自己这些年来的开发经验,把编程常用的英语单词都做了一次全面的汇总,总共700个计算机常用的单

    2023年04月20日
    浏览(26)
  • 读程序员的README笔记17_构建可演进的架构(下)

    1.3.3.1. 开发人员可以只专注于和自己相关的字段,因为它们会继承其他字段的默认值 1.3.3.2. 默认值可使大型API在感觉上很小巧 1.4.1.1. OpenAPI通常用于RESTful服务 1.4.1.2. non-REST服务则使用Protocol Buffers、Thrift或类似的接口定义语言(interface definition language,IDL) 1.4.1.3. 接口定义工

    2024年02月04日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包