如何在字符串里查找第一个不重复的字母,即只出现一次的最靠前的字母

本文详细解析了C语言中数组初始化赋值的原则,特别关注了使用花括号{}

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

      我在写这个程序时突然想起一个问题,就是C语言里给int一维数组初始化赋值的问题,比如我写:

int index[11]={0}; 那么此时数组中所有的元素初始化值均为0;但是我写:

int index[11]={-1};此时我以为所有元素的值均为-1了,其实不是这样的,当{}中的值的个数小于数组元素个数时,只有数组前面对应的元素被赋值了,而后面多余的元素被默认初始化为0了,所以这句话执行后,只有index[0]的值为-1,而其余元素均为0;但是如果我这样写:

int index[11]; 那么你也不要天真地以为所有元素默认值均为0,其实不然,这样写的话,所有元素的值均为随机值。

 

这就是数组初始化时我们应该注意的地方。好了,下面说说这个算法:

源代码如下:

 

#include <iostream>

using namespace std;

char findIt(const char *str);
int main()
{
    char str[]="iamastudenti";

    cout << findIt(str) << endl;
    return 0;
}

char findIt(const char *str)
{
    int count[26]={0};
    int index[26]={0};  //注意int数组初始化赋值时,如果写成={-1}是不能给所有元素初始化为-1的,只有第一个元素是-1,其余为默认值0
    unsigned int i;
    int pos;
    for(i=0;i<strlen(str);i++)
    {
        count[str[i]-'a']++;   //记录该字母出现的次数
       // cout<<count[str[i]-'a']<<endl;
        if(index[str[i]-'a']==0)
        {
            index[str[i]-'a']=i;  //记住该字母第一次出现时的索引
        }
    }
    pos=strlen(str);
    for(i=0;i<26;i++)
    {
        if(count[i]==1)  //找到只出现一次的字母
        {
            if(index[i]!=-1&&index[i]<pos)  //在只出现一次的字母中找出索引值最小的即可
            {
                pos=index[i];
            }
        }
    }
    if(pos<strlen(str))
        return str[pos];
    return '\0';
}

 

<think>好的,用户想要在C++中实现一个函数,找到字符串后一个仅出现一次的字符。我需要仔细思考如何解决这个问题,确保代码高效正确。首先,我得明确需求:后一个只出现一次的字符,也就是所有唯一字符中后出现的那个。例如,字符串“abba”中,后一个唯一字符存在,而“abcab”中的后一个唯一字符是'c'。 首先,我需要考虑如何统计每个字符的出现次数。通常的做法是使用哈希表或者数组来记录频率。对于ASCII字符,可以使用一个大小为256的数组来统计,这样效率更高。遍历字符串,统计每个字符出现的次数,这一步的时间复杂度是O(n),其中n是字符串长度。 接下来,需要再次遍历字符串找到后一个出现次数为1的字符。这需要注意的是,要从字符串的末尾开始向遍历,一旦遇到第一个出现次数为1的字符,就立即返回它,这样就能保证找到的是后一个符合条件的字符。这样第二次遍历的时间复杂度也是O(n),总的时间复杂度为O(n),空间复杂度是O(1)(因为数组大小固定为256)。 过,我需要确认是否所有可能的字符都被考虑到,包括大小写字母、数字、特殊字符等。假设题目中的字符是扩展的ASCII字符,所以数组大小设为256是正确的。此外,要注意字符串为空的情况,这时候应该返回空字符或者某种标识。 现在考虑边界情况。例如,字符串全为重复字符,这时候应该返回空或者null。或者字符串只有一个字符,直接返回该字符。还有像所有字符都唯一的情况,返回后一个字符。 然后,编写代码的大致步骤: 1. 初始化一个大小为256的数组,初始值为0。 2. 第一次遍历字符串,统计每个字符的出现次数。 3. 第二次从后往遍历字符串,检查每个字符的计数是否为1,第一个符合条件的字符即为答案。 测试几个例子: 比如输入“leetcode”,字符出现次数为l:1, e:3, t:1, c:1, o:1, d:1。从后往找,后一个出现次数1的是'd'?,原字符串是'l','e','e','t','c','o','d','e'。后的字符是'e',但'e'出现三次,所以应检查面的字符。后一个出现次数1的应该是'c'?或者可能我记错了例子。比如另一个例子“aabbcdd”,后一个唯一字符是'c',对吗? 代码实现部分,需要注意字符串的遍历顺序。例如,在第二次遍历时,从str.size()-1开始,递减到0,检查每个字符对应的count是否为1。一旦找到,立即返回该字符。 可能的优化:可以将两次遍历合一次,但这样可能需要存储每个字符一次出现的位置,然后找出其中出现次数为1且位置大的那个。但这样空间复杂度可能更高,因为需要保存两个数组:频率和后出现的位置。过,对于这个问题,两次分开遍历可能更简单且效率相当。 现在编写代码的结构: 函数参数是const string&,返回char。如果没找到,可以返回'\0'或者抛出异常,但根据题目要求,可能需要返回空字符。 代码示例: char findLastUniqueChar(const string &s) { vector<int> count(256, 0); for (char c : s) { count[static_cast<unsigned char>(c)]++; } for (int i = s.size() - 1; i >= 0; --i) { if (count[static_cast<unsigned char>(s[i])] == 1) { return s[i]; } } return '\0'; } 这要注意的是,字符可能是有符号的,所以转换为unsigned char来避免负的索引。例如,如果字符是0xFF,在signed char中会被视为-1,导致数组越界。所以必须用static_cast<unsigned char>来转换,确保索引在0-255之间。 测试用例: 测试1:字符串“aabccdeff”,每个字符出现次数为a:2, b:1, c:2, d:1, e:1, f:2。从后往遍历,后一个出现次数1的是'e'?或者检查每个字符的顺序。字符串的顺序是a,a,b,c,c,d,e,f,f。从后往是f,f,e,d,c,c,b,a,a。第一个count为1的是e,对吗?是的,所以返回'e'。 测试2:字符串“abcabc”,所有字符出现两次,返回空。 测试3:字符串“z”,返回'z'。 这样看来,代码是正确的。 另外,需要考虑输入为空的情况,此时返回'\0'。用户可能希望返回一个特定的值,比如空字符,或者使用std::optional,但根据问题描述,可能直接返回空字符即可。 总结下来,这样的实现应该是正确且高效的。时间复杂度O(n),空间O(1)。符合要求。</think>### 查找字符串后一个仅出现一次的字符(C++实现) 要实现查找字符串后一个仅出现一次的字符,可以分两步完成:统计字符频率,然后逆序遍历寻找目标字符。 **步骤说明** 1. **统计字符出现次数** 使用长度为256的数组(覆盖扩展ASCII字符)记录每个字符的出现次数。 ```cpp vector<int> count(256, 0); for (char c : s) { count[static_cast<unsigned char>(c)]++; } ``` 2. **逆序查找首个唯一字符** 从字符串末尾向遍历,找到第一个计数为1的字符: ```cpp for (int i = s.size() - 1; i >= 0; --i) { if (count[static_cast<unsigned char>(s[i])] == 1) { return s[i]; } } return '\0'; // 未找到时返回空字符 ``` **完整代码** ```cpp #include <vector> #include <string> using namespace std; char findLastUniqueChar(const string &s) { vector<int> count(256, 0); for (char c : s) { count[static_cast<unsigned char>(c)]++; } for (int i = s.size() - 1; i >= 0; --i) { if (count[static_cast<unsigned char>(s[i])] == 1) { return s[i]; } } return '\0'; // 无唯一字符时返回空字符 } ``` **复杂度分析** - **时间复杂度**:$O(n)$,两次线性遍历字符串。 - **空间复杂度**:$O(1)$,固定大小的计数数组。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值