力扣刷题之2306.公司命名

题干描述

给你一个字符串数组 ideas 表示在公司命名过程中使用的名字列表。公司命名流程如下:

  1. ideas 中选择 2 个 不同 名字,称为 ideaAideaB
  2. 交换 ideaAideaB 的首字母。
  3. 如果得到的两个新名字 不在 ideas 中,那么 ideaA ideaB串联 ideaAideaB ,中间用一个空格分隔)是一个有效的公司名字。
  4. 否则,不是一个有效的名字。

返回 不同 且有效的公司名字的数目。

示例 1:

复制代码
输入:ideas = ["coffee","donuts","time","toffee"]
输出:6
解释:下面列出一些有效的选择方案:
- ("coffee", "donuts"):对应的公司名字是 "doffee conuts" 。
- ("donuts", "coffee"):对应的公司名字是 "conuts doffee" 。
- ("donuts", "time"):对应的公司名字是 "tonuts dime" 。
- ("donuts", "toffee"):对应的公司名字是 "tonuts doffee" 。
- ("time", "donuts"):对应的公司名字是 "dime tonuts" 。
- ("toffee", "donuts"):对应的公司名字是 "doffee tonuts" 。
因此,总共有 6 个不同的公司名字。

下面列出一些无效的选择方案:
- ("coffee", "time"):在原数组中存在交换后形成的名字 "toffee" 。
- ("time", "toffee"):在原数组中存在交换后形成的两个名字。
- ("coffee", "toffee"):在原数组中存在交换后形成的两个名字。

示例 2:

复制代码
输入:ideas = ["lack","back"]
输出:0
解释:不存在有效的选择方案。因此,返回 0 。

题干分析

已知该算法题的目标是计算可以生成的不同名称组合的数量。具体来说就是给定一组字符串"ideas",每个字符串可以通过交换首字母的的方式与另一个字符串组合形成新的字符串对。要求计算总共可以生成多少个不同的字符串对,且这两个字符串组合后形成的新字符串不能出现在原始的字符串列表中。

解题思路

1.分组处理:
  • 将所有的字符串按照他们的首字母进行分类。假设字符串有26个字母组成,可以将所有字符串按首字母a-z分成26个组。每组中的字符串去掉首字母后,只保留其余部分。
2.交集与组合计算:
  • 对每一组,将其与其他组进行比较,找出可以交换的字符串对。
  • 如果两个组有相同的尾部字符串,则这些字符串不能进行交换。因此我们需要计算两组间尾部字符串的交集大小。
  • 对于没有交集的字符串对,恶意直接交换首字母,生成合法的字符串对。
3.使用哈希表
  • 为了快速查找和操作相同尾部的字符串,使用哈希表来存储去掉首字母后的字符串。通过比较两个哈希表中的字符串,计算每两个组间的交集。

详细步骤

1.创建哈希表
  • 我们为每个首字母维护一个哈希表,哈希表中的key为去掉首字母后的字符串,value可以是一个空值,因为我们只关心字符串是否存在。
2.遍历每一个字符串
  • 根据字符串的首字母,将其分类到对应的哈希表,哈希表的key是去掉首字母后的字符串。
3.两两组比较
  • 计算组之间的交集大小,即两个哈希表中相同的字符串数目。
  • 计算两个组之间可以生成的不同字符串对数。
4.结果累加
  • 累加所有合法字符串对的数量。
5.释放内存
  • 遍历结束后,释放所有哈希表的内存。

代码解释

cpp 复制代码
#define MAX_STR_SIZE 16

typedef struct {
    char key[MAX_STR_SIZE];  // 字符串的key,存放去掉首字母后的字符串
    UT_hash_handle hh;  // 哈希表句柄
} HashItem; 

// 查找哈希表中的指定key项
HashItem *hashFindItem(HashItem **obj, const char* key) {
    HashItem *pEntry = NULL;
    HASH_FIND_STR(*obj, key, pEntry);  // 在哈希表中查找指定key
    return pEntry;
}

// 向哈希表中添加一个新的key
bool hashAddItem(HashItem **obj, const char* key) {
    if (hashFindItem(obj, key)) {  // 如果已经存在,返回false
        return false;
    }
    HashItem *pEntry = (HashItem *)malloc(sizeof(HashItem));  // 分配内存
    sprintf(pEntry->key, "%s", key);  // 将key复制到哈希表项中
    HASH_ADD_STR(*obj, key, pEntry);  // 向哈希表中添加key
    return true;
}

// 释放哈希表
void hashFree(HashItem **obj) {
    HashItem *curr = NULL, *tmp = NULL;
    HASH_ITER(hh, *obj, curr, tmp) {  // 迭代哈希表中的所有项
        HASH_DEL(*obj, curr);  // 删除当前项
        free(curr);  // 释放内存
    }
}

// 计算两个哈希表的交集大小
size_t get_intersect_size(const HashItem *a, const HashItem *b) {
    size_t ans = 0;
    for (HashItem *pEntry = a; pEntry; pEntry = pEntry->hh.next) {  // 遍历哈希表a
        if (hashFindItem(&b, pEntry->key)) {  // 如果b中也有相同的key
            ++ans;  // 交集大小加1
        }
    }
    return ans;
}

// 计算不同的名字组合数
long long distinctNames(char** ideas, int ideasSize) {
    HashItem *names[26] = {NULL};  // 存放26个字母对应的哈希表
    for (int i = 0; i < ideasSize; i++) {
        hashAddItem(&names[ideas[i][0] - 'a'], ideas[i] + 1);  // 根据首字母添加到对应哈希表
    }

    long long ans = 0;
    for (int i = 0; i < 26; i++) {
        if (names[i] == NULL) {  // 如果当前字母组为空,跳过
            continue;
        }
        int lenA = HASH_COUNT(names[i]);  // 获取当前组的字符串数量
        for (int j = i + 1; j < 26; j++) {
            if (names[j] == NULL) {  // 如果对比的字母组为空,跳过
                continue;
            }
            int lenB = HASH_COUNT(names[j]);  // 获取对比组的字符串数量
            int intersect = get_intersect_size(names[i], names[j]);  // 计算两个组的交集
            ans += 2 * (lenA - intersect) * (lenB - intersect);  // 计算合法的字符串对数
        }
    }
    for (int i = 0; i < 26; i++) {
        hashFree(&names[i]);  // 释放哈希表
    }
    return ans;
}
相关推荐
zyhomepage3 分钟前
科技的成就(六十三)
linux·开发语言·人工智能·科技·算法·游戏·内容运营
源代码•宸19 分钟前
小米2025届软件开发工程师(C/C++/Java)(编程题AK)
c语言·c++·经验分享·算法·动态规划
深山夕照深秋雨mo26 分钟前
机器人的运动范围
算法·机器人
宇宙超粒终端控制中心1 小时前
leetcode35--搜索插入位置--二分查找刷题
数据结构·二分查找
凡人的AI工具箱2 小时前
15分钟学 Python 第31天 :Web Scraping
开发语言·数据结构·人工智能·python·算法
Starry_hello world3 小时前
双链表(纯代码)
数据结构·笔记·有问必答
luthane3 小时前
python 实现rayleigh quotient瑞利商算法
开发语言·python·算法
Jcqsunny3 小时前
[dp] 小信走迷宫
算法·前缀和·动态规划·dp
鱼跃鹰飞3 小时前
Leecode热题100-48.旋转图像
java·后端·算法·leetcode·面试
luthane3 小时前
python 实现knapsack背包问题算法
开发语言·python·算法