力扣刷题之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;
}
相关推荐
网易独家音乐人Mike Zhou2 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
搬砖的小码农_Sky5 小时前
C语言:数组
c语言·数据结构
Swift社区6 小时前
LeetCode - #139 单词拆分
算法·leetcode·职场和发展
Kent_J_Truman6 小时前
greater<>() 、less<>()及运算符 < 重载在排序和堆中的使用
算法
先鱼鲨生7 小时前
数据结构——栈、队列
数据结构
一念之坤7 小时前
零基础学Python之数据结构 -- 01篇
数据结构·python
IT 青年7 小时前
数据结构 (1)基本概念和术语
数据结构·算法
熬夜学编程的小王7 小时前
【初阶数据结构篇】双向链表的实现(赋源码)
数据结构·c++·链表·双向链表
Dong雨7 小时前
力扣hot100-->栈/单调栈
算法·leetcode·职场和发展
SoraLuna7 小时前
「Mac玩转仓颉内测版24」基础篇4 - 浮点类型详解
开发语言·算法·macos·cangjie