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

最长字符串链(String Chains)

题目描述

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

示例

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
输入:

6
a
b
ba
bca
bda
bdca

输出:

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代码

#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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值