【动态规划算法题记录】NV某笔试题目(哈希+dp)

最长字符串链(String Chains)

题目描述

给定一个表示字典的单词数组,测试每个单词,查看它是否可以通过逐一去除字符变为字典中的另一个单词。每个单词代表其字符串链的第一个元素,因此字符串链的初始长度为1。每次去除一个字符时,将字符串链的长度增加1。为了移除一个字符,生成的单词必须在原始字典中。确定给定字典可以实现的最长字符串链。

示例

bash 复制代码
n = 4
words = ['a', 'and', 'an', 'bear']

单词 and 可以被简化为 an,然后再简化为 a。字符 a 不能再进一步简化,因为字典中没有空字符串。单词 bear 无法简化。最长的字符串链长度为 3。

longestChain 有以下参数:

int n:单词数组的长度

str words[n]:要测试的字符串字典

返回值:

int:最长字符串链的长度

约束条件
1 ≤ n ≤ 50000
1 ≤ |words[i]| ≤ 60,其中 0 ≤ i < n

每个 words[i] 由范围 ascii[a-z] 的小写字母组成

输入格式:

第一行包含一个整数 n,表示 words 数组的大小。

接下来的 n 行中,每行包含一个值 words[i],其中 0 ≤ i < n。

示例案例 0
输入:

bash 复制代码
6
a
b
ba
bca
bda
bdca

输出:

bash 复制代码
4

解释:

words = ["a", "b", "ba", "bca", "bda", "bdca"]

由于 a 和 b 是单字符单词,它们不能被简化。这会导致空字符串,因此它们的字符串链长度为 1。

单词 ba 可以创建两个不同的字符串链,每个长度为 2:("ba"→ "a" 和 "ba"→ "b")。此时当前最长字符串链长度为 2。

单词 bca 可以创建两个不同的字符串链,每个长度为 3:("bca"→ "ba"→ "a" 和 "bca"→ "ba"→ "b")。此时当前最长字符串链长度为 3。

单词 bda 可以创建两个不同的字符串链,每个长度为 3:("bda"→ "ba"→ "a" 和 "bda"→ "ba"→ "b")。此时当前最长字符串链长度仍然为 3。

单词 bdca 可以创建四个不同的字符串链,每个长度为 4:("bdca"→ "bda"→ "ba"→ "a","bdca"→ "bca"→ "ba"→ "b","bdca"→ "bda"→ "ba"→ "b")。当前最长字符串链长度为 4。

最长字符串链的长度为 4。

思路分析

哈希表+dp:

  1. 哈希表存放字典中的每个单词的字符串链数量,初始都为1。
  2. 将字典按照字符个数从小到大排列
  3. dp[i]是第i个单词的最长字符串链数量,递推公式 dp["abc"] = dp["ab"] + dp["ac"] + dp["bc"]。具体见代码。

cpp代码

cpp 复制代码
#include <bits/stdc++.h>

using namespace std;

string ltrim(const string &);
string rtrim(const string &);

#include <unordered_map>
/*
 * Complete the 'longestChain' function below.
 *
 * The function is expected to return an INTEGER.
 * The function accepts STRING_ARRAY words as parameter.
 */

int longestChain(vector<string> words) {
    // 对words单词长短进行排序
    sort(words.begin(), words.end(), [](const string& a, const string& b){
        return a.length() < b.length();
    });
    int ans = 1;
    // dp["abc"]:字符串abc的最长字符链
    // 递推公式 dp["abc"] = dp["ab"] + dp["ac"] + dp["bc"]
    unordered_map<string, int> dp; // key:字典中的单词,value:出现次数
    for(const string& s : words){
        dp[s] = 1;
        for(int i = 0; i < s.size(); ++i){
            string subs = s.substr(0, i) + s.substr(i+1);
            if(dp.find(subs) != dp.end()){
                dp[s] = max(dp[s], dp[subs] + 1);
            }
        }
        ans = max(ans, dp[s]);
    }
    return ans;
}

int main()
{
    ofstream fout(getenv("OUTPUT_PATH"));

    string words_count_temp;
    getline(cin, words_count_temp);

    int words_count = stoi(ltrim(rtrim(words_count_temp)));

    vector<string> words(words_count);

    for (int i = 0; i < words_count; i++) {
        string words_item;
        getline(cin, words_item);

        words[i] = words_item;
    }

    int result = longestChain(words);

    fout << result << "\n";

    fout.close();

    return 0;
}

string ltrim(const string &str) {
    string s(str);

    s.erase(
        s.begin(),
        find_if(s.begin(), s.end(), not1(ptr_fun<int, int>(isspace)))
    );

    return s;
}

string rtrim(const string &str) {
    string s(str);

    s.erase(
        find_if(s.rbegin(), s.rend(), not1(ptr_fun<int, int>(isspace))).base(),
        s.end()
    );

    return s;
}

总结

总体来说nv的难度没有特别难,但是英文看着好吃力。。。QAQ

相关推荐
游是水里的游22 分钟前
【算法day19】回溯:分割与子集问题
算法
不想当程序猿_23 分钟前
【蓝桥杯每日一题】分糖果——DFS
c++·算法·蓝桥杯·深度优先
南城花随雪。42 分钟前
单片机:实现FFT快速傅里叶变换算法(附带源码)
单片机·嵌入式硬件·算法
dundunmm1 小时前
机器学习之scikit-learn(简称 sklearn)
python·算法·机器学习·scikit-learn·sklearn·分类算法
古希腊掌管学习的神1 小时前
[机器学习]sklearn入门指南(1)
人工智能·python·算法·机器学习·sklearn
波音彬要多做1 小时前
41 stack类与queue类
开发语言·数据结构·c++·学习·算法
程序员老冯头3 小时前
第十五章 C++ 数组
开发语言·c++·算法
AC使者8 小时前
5820 丰富的周日生活
数据结构·算法
cwj&xyp8 小时前
Python(二)str、list、tuple、dict、set
前端·python·算法
xiaoshiguang312 小时前
LeetCode:222.完全二叉树节点的数量
算法·leetcode