【动态规划算法题记录】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

相关推荐
理论最高的吻25 分钟前
98. 验证二叉搜索树【 力扣(LeetCode) 】
数据结构·c++·算法·leetcode·职场和发展·二叉树·c
沈小农学编程30 分钟前
【LeetCode面试150】——202快乐数
c++·python·算法·leetcode·面试·职场和发展
ZZZ_O^O43 分钟前
【动态规划-卡特兰数——96.不同的二叉搜索树】
c++·学习·算法·leetcode·动态规划
一只小透明啊啊啊啊1 小时前
Leetcode100子串
算法
木向1 小时前
leetcode:114. 二叉树展开为链表
算法·leetcode·链表
sky_smile_Allen1 小时前
[C#] 关于数组的详细解释以及使用注意点
开发语言·算法·c#
希望有朝一日能如愿以偿2 小时前
力扣题解(新增道路查询后的最短距离II)
算法
我感觉。2 小时前
【机器学习chp6】对数几率回归
算法·机器学习·逻辑回归·分类模型·对数几率回归
无限大.2 小时前
力扣题解3248 矩阵中的蛇(简单)
算法·leetcode·矩阵
灼华十一2 小时前
算法编程题-排序
数据结构·算法·golang·排序算法