LeetCode771 宝石与石头

题目描述

给定一个字符串 jewels,它代表石头中宝石的类型;另有一个字符串 stones,代表我们拥有的石头。其中,stones 里的每个字符对应一种石头类型,任务是要精准地统计出在 stones 当中,属于 jewels 所定义的宝石类型的石头究竟有多少。这里需特别注意,字母区分大小写,像 "a""A" 会被视作不同类型的石头。

解题思路

暴力解法:双层循环遍

最初想到的最直白的方法,就是利用双层 for 循环嵌套。外层循环负责逐个遍历 stones 中的字符,对于每一个 stones 里的字符,内层循环则遍历 jewels 字符串,去逐一比对是否有匹配的宝石类型。一旦找到匹配项,立马给计数器 count 加 1,随后中断内层循环,继续检查 stones 的下一个字符。

cs 复制代码
#include <stdio.h>
#include <string.h>

// 函数用于统计在stones中属于jewels定义的宝石类型的字符个数
int numJewelsInStones(char* jewels, char* stones) {
    int count = 0;
    // 遍历stones字符串中的每个字符
    for (int i = 0; stones[i]!= '\0'; i++) {
        // 对于stones中的每个字符,遍历jewels字符串进行匹配
        for (int j = 0; jewels[j]!= '\0'; j++) {
            if (stones[i] == jewels[j]) {
                count++;
                break;  // 一旦匹配成功,就不用继续在jewels中找了,直接去看下一个stones中的字符
            }
        }
    }
    return count;
}

int main() {
    char jewels[] = "aA";  // 可以自行修改这里的宝石类型字符串内容
    char stones[] = "aAAbbbb";  // 可以自行修改这里的拥有石头类型字符串内容
    int result = numJewelsInStones(jewels, stones);
    printf("在拥有的石头中宝石的数量是: %d\n", result);
    return 0;
}

这种方法虽然易于理解,代码逻辑清晰,但时间复杂度不容小觑,达到了 O(m * n),其中 mstones 字符串长度,njewels 字符串长度。想象一下,当 stonesjewels 都很长时,计算量会呈指数级增长,效率明显受限。

方法二:

哈希表优化解法:空间换时间

为了突破暴力解法的效率瓶颈,哈希表闪亮登场。其核心思路是预先利用一个数组(这里模拟哈希表,假设 ASCII 码值范围能涵盖处理字符)来存储宝石类型信息。

首先,遍历 jewels 字符串,将其中出现的字符对应的数组位置标记为 1,这就像是给宝石类型做了个快速索引目录。接着,遍历 stones 字符串时,只需凭借字符的 ASCII 码值瞬间定位到数组对应位置,若值为 1,那该字符就是宝石类型,计数器 count 顺势加 1。

cs 复制代码
#include <stdio.h>
#include <string.h>

// 函数用于统计在stones中属于jewels定义的宝石类型的字符个数
int numJewelsInStones(char* jewels, char* stones) {
    int hashTable[128] = {0};  // 假设ASCII码值范围足够涵盖我们要处理的字符,初始化哈希表数组元素都为0
    int count = 0;
    // 先将jewels中的字符对应的哈希表位置标记为1,表示存在这样的宝石类型
    for (int i = 0; jewels[i]!= '\0'; i++) {
        hashTable[(int)jewels[i]] = 1;
    }
    // 遍历stones,通过哈希表快速判断是否是宝石类型
    for (int j = 0; stones[j]!= '\0'; j++) {
        if (hashTable[(int)stones[j]] == 1) {
            count++;
        }
    }
    return count;
}

int main() {
    char jewels[] = "aA";  // 可根据需求修改宝石类型字符串内容
    char stones[] = "aAAbbbb";  // 可根据需求修改拥有石头类型字符串内容
    int result = numJewelsInStones(jewels, stones);
    printf("在拥有的石头中宝石的数量是: %d\n", result);
    return 0;
}

经此优化,时间复杂度大幅降至 O(m + n),尽管额外开辟了数组空间用于存储哈希表信息,但在数据量庞大时,计算效率的提升立竿见影,完美诠释了 "空间换时间" 的编程技巧精髓。

总结与启示

这道题犹如一面镜子,清晰映照出编程中效率权衡的艺术。从简单直接的暴力解法,到巧用数据结构优化的进阶之路,我们领悟到面对问题,思维不能局限于最初的直观想法。当性能瓶颈显现,积极探寻更优算法结构、大胆借助数据结构独特优势,才能在程序执行效率的赛道上弯道超车。

无论是日常刷题备战面试,还是实际项目开发优化性能,这种不断打磨解法、追求极致的精神,都将成为我们手中披荆斩棘的利刃,助力我们在代码世界里畅行无阻,攻克一个又一个难题。希望这次分享能给大家带来新的启发,一起在编程之旅中不断进阶!

相关推荐
octopus_c15 分钟前
数据结构:堆(Heap)详解
c语言·数据结构·算法
YH55269846 小时前
GPT‑5.6 Sol 原本支持 1M 上下文,Codex 现已放开此前限制,如何看待这次调整?
java·jvm·人工智能·gpt·算法·chatgpt
遥感知识服务8 小时前
从局部阈值、双极化到暗地表剔除:NASA OPERA DSWx-S1全球动态水体算法拆解
大数据·人工智能·深度学习·神经网络·算法·机器学习
晚风醉蝶8 小时前
1-13-TimSort
算法
ZJU_统一阿萨姆8 小时前
【算子开发】算子融合与Softmax_LayerNorm实现
人工智能·算法·语言模型·硬件架构
叩码以求索10 小时前
浅谈:前序遍历反转法求解N叉树的后序遍历
算法
北风toto11 小时前
中缀、前缀、后缀表达式
算法·软件设计师
听取WA声一片(无恶意)11 小时前
CSP-J/CSP-S 深度优先搜索(DFS)完全讲义
c++·算法·深度优先
码流怪侠12 小时前
2026年8月GitHub热榜深度拆解:Agent Skills席卷开源圈,一个“技能包“收割5万星
算法·程序员·github
hold?fish:palm12 小时前
30 两两交换链表中的节点
数据结构·算法·链表