【阶段试题分析】统计一个字符串中重复的字符串问题

本文提供三种方法来解决寻找给定字符串中重复出现的字符串及其出现次数的问题,包括使用IndexOf方法、避免重复比对及优化查找过程。

 

题目:有字符串: qabaabbwerabtyababuiopasdfghjkabl,请写一段程序,找出重复出现的字符串(长度大于1的连续字符组合),以及他们出现的次数。通过控制台打印出来。

比如:

ab,6

aba,2

ba,2

思路:自己想的是先从整串中先取出2个字符,然后与剩下的字符串中取出2个字符逐一比较,显然我忽略了一些问题:遍历到已经对比过的字符串时重复计入了结果当中

自己需要注意的问题:考虑去除重复比对的字符串;分割比对的字符串是最大位置就是代码一中的(str.length-i),不用自己想想的那么麻烦;string中有IndexOf方法去查找包含字符的位置。

下面是同学写的一些方法,供参考:

代码一:

/*************************************************
 * 题目三:统计重复字符串
 * *********************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FindRepeatString
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("请输入您要查找的字符串");
            //string str = Console.ReadLine().Trim();
            //string str = "qabaabbwerabtyababuiopasdfghjkabl";
            string str = "abccabccab";
            FindStringCount(str);
            Console.ReadKey();
        }

        /// <summary>
        /// 查找字符串中重复出现的字符串在字符串中出现的次数
        /// </summary>
        /// <param name="str">要查找的字符串</param>
        private static void FindStringCount(string str)
        {
            //判断截取的字符串是否已经查找过了
            bool flagStr = false;
            //截取的字符串集合
            List<string> strList = new List<string>();
            //查找到的次数
            int count = 0;

            //比较需要查找的字符个数是否大于1个
            if (str.Length > 1)
            {
                for (int i = 2; i < str.Length; i++)       //分割字符串,从2个开始,一直到最大
                {
                    //分割位置,从字符串第一个字符开始分割,一直到分割到最大字符-分割字符的个数
                    for (int n = 0; n < str.Length - i; n++)     
                    {
                        string newstr = str.Substring(n, i);    //分割需要比对的字符串
                        
                        flagStr = false;       //默认为没有判断过的
                        
                        if (strList.Contains(newstr))  //判断字符串是否已经判断过了
                        {
                            flagStr = true;
                        }
                        //如果字符串判断过了就不用判断,如果没有判断就开始查找重复出现了多少次
                        if (!flagStr)  
                        {
                            strList.Add(newstr);    //将字符串加入已经判断的字符串中去

                            for (int k = 0; k < str.Length; k++)        //将提取的字符串与整串进行比对
                            {
                                
                                int indexOf = str.IndexOf(newstr, k);    //如果有该字符串存在则返回位置,无返回-1

                                if (indexOf == -1)   //判断是否有或者是否已经查找完毕了
                                {
                                    break;
                                }

                                //例如ab c ab cc ab ,先用ab比对得到第一ab位置,再 
                                k = indexOf;    

                                count++;    //记录出现次数加1
                            }

                            //每个字符串肯定都会出现一次,是他本身,出现一次不打印
                            if (count > 1)
                            {
                                Console.WriteLine(newstr + "在字符串中出现了" + count + "");
                            }
                            //一个字符串判断玩了,字符串清0
                            count = 0;
                        }
                    }
                    //分割不同个数的字符肯定不会一样,这里清空以查找的字符串,提高效率,很明显,2个字符和3个字符肯定不同
                    strList.RemoveRange(0, strList.Count);
                }
            }
            else
            {
                Console.WriteLine("请输入的字符串大于1个字符");
            }
        }
    }
}

代码二:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FindRepeatString
{
    /// <summary>
    /// 给定字符串,查找其中重复的子字符串积重复的次数
    /// </summary>
    class Program
    {
        /// <summary>
        /// 程序入口
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            //Console.WriteLine("请输入字符串");
            //string str = Console.ReadLine();

            string str = "qabaabbwerabtyababuiopasdfghjkabl";
            FindTheRepeatString(str);
            Console.ReadLine();
        }

        /// <summary>
        /// 查找字符串中重复子字符串出现的次数
        /// </summary>
        /// <param name="str">待查字符串</param>
        public static void FindTheRepeatString(string str)
        {
            //字符串起始位置
            for (int start = 0; start < str.Length; start++)
            {
                //字符串的长度
                for (int len = 2; len < str.Length - start + 1; len++)
                {
                    //获取字符串
                    string pi = str.Substring(start,len);

                    //判断该截取字符串是否已经查找过,如果查找过则不再重复查找
                    if (str.Substring(0,start).Contains(pi))
                    {
                        continue;
                    }

                    //获取出现的次数
                    int count = CountNumber(str, pi);

                    //输出出现次数大于1的子字符串
                    if (count > 1)
                    {
                        Console.WriteLine(pi + "重复出现" + count + "");
                    }
                }
            }
        }

        /// <summary>
        /// 统计字符串出现的次数
        /// </summary>
        /// <param name="str">原始字符串</param>
        /// <param name="pi">子字符串</param>
        /// <returns></returns>
        public static int CountNumber(string str, string pi)
        {
            int count = 0;
            //子字符串的步长起始位置
            int subStart = -1;

            while (true)
            {
                //每次从剩下的子字符串中去查找匹配字符串的索引位置,如果为-1,则没有查找到
                int index = str.Substring(subStart + 1).IndexOf(pi);
                if (index == -1)
                {
                    break;
                }
                count++;
                subStart += index + 1;
            }
            return count;
        }
    }
}

代码三:

/*********************************************************************************
 *
 * 功能描述:    重复字符串计数
 *
 * 作    者:    yimeng
 *
 * 修改日期:    2013-8-18
 * 
 * 备    注:    有字符串:qabaabbwerabtyababuiopasdfghjkabl,请写一段程序,找出
 *                 重复出现的字符串(长度大于1的连续字符组合),以及他们出现的次数。
 *                 通过控制台打印出来。比如:
 *                 ab,6
 *                 aba,2
 *                 ba,2
************************************************************************************/

namespace MiddleExam
{
    using System;
    using System.Collections.Generic;

    /// <summary>
    /// 重复字符串计数
    /// </summary>
    class RepeatedString
    {
        /// <summary>
        /// 给定的字符串
        /// </summary>
        private const string myString = "qabaabbwffffffffffffhfhgfhgfyababuiopasdfghjkabl";//qabaabbwerabtyababuiopasdfghjkabl

        /// <summary>
        /// 重复字符串计数
        /// </summary>
        public static void GetRepeatedStringCount()
        {
            //首先把给定的字符串中,长度大于2的连续字符串找出来,放到一个集合里
            List<string> stringList = GetContinueStringOfLengthGreaterThan2(myString);

            //遍历集合,对集合中每个字符串进行处理
            foreach (string str in stringList)
            {
                int count = GetStringAppearCount(myString, str);

                //出现次数大于1的,打印出来
                if (count > 1)
                {
                    Console.WriteLine("{0},{1}", str, count);
                }
            }
            Console.ReadLine();
        }

        /// <summary>
        /// 找出连续两个以上字符串,并放到一个集合中。
        /// 注意:已经去掉重复的
        /// </summary>
        /// <param name="theString">带处理的字符串</param>
        /// <returns>
        /// 字符串集合
        /// </returns>
        /// <remarks>
        /// 基本思路:
        /// 1.从位置0开始,截取长度为2的字符串,然后往前进一位,继续截取长度为2的字符串,以此类推,直到末尾。
        /// 2.从位置0开始,截取长度为3的字符串,然后往前进一位,继续截取长度为3的字符串,以此类推,直到末尾。
        /// 3.以此类推
        /// </remarks>
        private static List<string> GetContinueStringOfLengthGreaterThan2(string theString)
        {
            //定义一个空的字符串集合
            List<string> stringList = new List<string>();

            //截取字符串的长度:从2开始,依次递增。
            for (int i = 2; i <= theString.Length; i++)
            {
                //截取的位置:从0开始,依次递增,但不能超过【总长度-截取的长度】。
                for (int j = 0; j <= theString.Length - i; j++)
                {
                    string str = theString.Substring(j, i);//开始截取

                    if (!stringList.Contains(str))//除重
                    {
                        stringList.Add(str);
                    }
                }
            }

            return stringList;
        }

        /// <summary>
        /// 获取一个指定的字符串在某个字符串中出现的次数
        /// </summary>
        /// <param name="originalString">源字符串</param>
        /// <param name="theString">给定字符串</param>
        /// <returns>出现的次数</returns>
        /// <remarks>
        /// 基本思路:
        /// 查找theString出现的位置,找到后,继续往下找,每次找计数器都加1。
        /// </remarks>
        private static int GetStringAppearCount(string originalString, string theString)
        {
            int count = 0;

            //找到theString第一次出现的位置
            int index = originalString.IndexOf(theString);

            /*
             * 如果theString出现过,则不断循环,从theString出现的位置的下一位开始再查找,
             * 看看是否还出现,以此类推,直到没有找到,则跳出循环
             */
            while (index >= 0)
            {
                //找到,则计数器加1
                count++;
                //找到后,把originalString从【出现位置的下一位,总长度-出现位置-1】截取出来
                originalString = originalString.Substring(index + 1, originalString.Length - index - 1);
                //进行下一次查找
                index = originalString.IndexOf(theString);
            }

            return count;
        }
    }
}

 

 

 

转载于:https://www.cnblogs.com/qingsongwang/p/3266062.html

<think>我们面临的问题:在MySQL中判断一个字符串是否包含重复字符。 思路分析: 1. 没有直接函数可以判断,需要自定义函数或使用SQL技巧。 2. 我们可以尝试将字符串拆分成单个字符,然后统计每个字符出现的次数,如果有任何字符出现次数大于1,则说明有重复。 方法: 方法一:使用自定义函数(UDF)循环遍历字符串中的每个字符,并检查是否重复。 方法二:利用MySQL 8.0的递归CTE(公共表表达式)将字符串拆分为字符,然后进行分组统计。 由于问题中没有说明MySQL版本,我们提供两种方案。 方案一:适用于MySQL 8.0及以上(使用递归CTE) 步骤: 1. 将字符串拆分成单个字符。 2. 对字符进行分组,统计每个字符出现的次数。 3. 判断是否有字符出现次数大于1。 示例代码(假设要判断的字符串为'abcda'): ```sql WITH RECURSIVE split_chars AS ( SELECT SUBSTRING('abcda', 1, 1) AS char, 1 AS pos UNION ALL SELECT SUBSTRING('abcda', pos+1, 1), pos+1 FROM split_chars WHERE pos < LENGTH('abcda') ) SELECT char, COUNT(*) AS count FROM split_chars GROUP BY char HAVING count > 1; ``` 如果上述查询返回结果,则说明有重复字符。 方案二:使用自定义函数(适用于所有版本) 我们可以创建一个函数,使用循环遍历字符串中的每个字符,并检查后续是否再次出现。 函数定义: ```sql DELIMITER $$ CREATE FUNCTION has_duplicate_chars(str VARCHAR(255)) RETURNS BOOLEAN DETERMINISTIC BEGIN DECLARE i INT DEFAULT 1; DECLARE j INT; DECLARE len INT; DECLARE char_i CHAR(1); DECLARE char_j CHAR(1); SET len = LENGTH(str); -- 如果字符串长度大于256(假设是ASCII字符集),那么必然有重复(根据抽屉原理),但这里我们不考虑字符集,而是直接遍历 -- 注意:也可以先判断长度,如果长度大于字符集可能的不同字符数(比如ASCII是256),则直接返回1(有重复),但这里我们简单处理 WHILE i <= len DO SET char_i = SUBSTRING(str, i, 1); SET j = i + 1; WHILE j <= len DO SET char_j = SUBSTRING(str, j, 1); IF char_i = char_j THEN RETURN TRUE; END IF; SET j = j + 1; END WHILE; SET i = i + 1; END WHILE; RETURN FALSE; END$$ DELIMITER ; ``` 使用示例: ```sql SELECT has_duplicate_chars('abcda'); -- 返回1(表示有重复) SELECT has_duplicate_chars('abcde'); -- 返回0(无重复) ``` 注意:自定义函数在创建需要相应权限。 方案三:利用MySQL 8.0的JSON函数(如果不能用递归CTE,但版本是8.0以上,也可以使用JSON函数拆分) 例如: ```sql SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('abcda', '', n.digit+1), '', -1) AS char, COUNT(*) AS count FROM (SELECT 0 AS digit UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 ... ) AS n WHERE n.digit < LENGTH('abcda') GROUP BY char HAVING count > 1; ``` 但是这里需要一张数字辅助表(从0到字符串最大长度),我们可以用递归CTE生成数字序列,但如果没有递归CTE,则需要预先生成。 考虑到通用性,自定义函数方法(方案二)更通用。 总结: 1. 如果MySQL版本是8.0及以上,可以使用递归CTE方法(方案一)进行查询,无需创建函数。 2. 如果版本较低,或者需要频繁使用,可以创建自定义函数(方案二)。 相关问题: 1. 如何优化自定义函数`has_duplicate_chars`的性能? 2. 在MySQL中如何拆分字符串为单个字符? 3. 如何统计字符串中每个字符的出现频率? 4. 在MySQL中如何判断字符串是否包含重复字符(不区分大小写)? 5. 如何用一条SQL语句同判断多个字符串是否包含重复字符? 注意:在自定义函数中,我们使用了嵌套循环,对于长字符串可能效率较低。优化思路:可以提前返回,一旦发现重复就返回,所以对于有重复字符串,可能很快返回,但无重复的需要完整遍历。另外,如果字符串很长,可以考虑使用哈希表(但MySQL函数中不支持复杂数据结构),或者先进行字符集判断(如字符串长度大于256且字符集为ASCII,则必然重复)等优化。 对于不区分大小写的情况,可以在比较之前将字符转换为大写或小写,例如:`IF LOWER(char_i) = LOWER(char_j) THEN`,同注意在拆分字符也要统一大小写。 以上方法供参考。</think>在 MySQL 中判断字符串是否包含重复字符,可以通过以下方法实现,结合字符串函数和子查询技术: ### 方法一:使用 LENGTH() 与 COUNT(DISTINCT) 比较(推荐) ```sql SELECT your_string AS original_string, LENGTH(your_string) - LENGTH(REPLACE(your_string, ',', '')) + 1 AS total_chars, COUNT(DISTINCT SUBSTRING_INDEX(SUBSTRING_INDEX(your_string, ',', n), ',', -1)) AS distinct_chars, CASE WHEN LENGTH(your_string) - LENGTH(REPLACE(your_string, ',', '')) + 1 > COUNT(DISTINCT SUBSTRING_INDEX(SUBSTRING_INDEX(your_string, ',', n), ',', -1)) THEN 'Has duplicates' ELSE 'No duplicates' END AS duplicate_check FROM ( SELECT 'a,b,c,d,a' AS your_string -- 替换为你的字段或字符串 ) t JOIN ( SELECT 1 AS n UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 -- 扩展至最大可能长度 ) numbers ON n <= LENGTH(your_string) - LENGTH(REPLACE(your_string, ',', '')) + 1; ``` **原理说明**: 1. `SUBSTRING_INDEX(SUBSTRING_INDEX(your_string, ',', n), ',', -1)` 将字符串拆分为单个字符 2. 比较总字符数 (`LENGTH() - LENGTH(REPLACE()) + 1`) 与去重后字符数 (`COUNT(DISTINCT)`) 3. 如果总字符数 > 去重字符数 → 存在重复字符 ### 方法二:使用 FIND_IN_SET() 检测重复(适用于逗号分隔值) ```sql SELECT your_string, EXISTS ( SELECT 1 FROM ( SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(your_string, ',', n), ',', -1) AS char FROM ( SELECT 1 AS n UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 -- 扩展至最大长度 ) nums WHERE n <= LENGTH(your_string) - LENGTH(REPLACE(your_string, ',', '')) + 1 ) chars GROUP BY char HAVING COUNT(*) > 1 ) AS has_duplicates FROM ( SELECT 'a,b,c,d,a' AS your_string -- 替换为你的字段 ) t; ``` ### 方法三:创建自定义函数(可复用) ```sql DELIMITER $$ CREATE FUNCTION has_duplicate_chars(str VARCHAR(255)) RETURNS BOOLEAN DETERMINISTIC BEGIN DECLARE i INT DEFAULT 1; DECLARE j INT; DECLARE len INT; DECLARE char_i CHAR(1); DECLARE char_j CHAR(1); SET len = LENGTH(str); WHILE i <= len DO SET char_i = SUBSTRING(str, i, 1); SET j = i + 1; WHILE j <= len DO SET char_j = SUBSTRING(str, j, 1); IF char_i = char_j THEN RETURN TRUE; END IF; SET j = j + 1; END WHILE; SET i = i + 1; END WHILE; RETURN FALSE; END$$ DELIMITER ; -- 使用示例 SELECT has_duplicate_chars('hello'); -- 返回1 (TRUE) SELECT has_duplicate_chars('world'); -- 返回0 (FALSE) ``` ### 性能优化建议 1. **预处理数据**:在数据写入进行去重处理 2. **使用生成列**(MySQL 5.7+): ```sql ALTER TABLE your_table ADD COLUMN is_duplicate BOOLEAN GENERATED ALWAYS AS (has_duplicate_chars(your_column)) STORED; ``` 3. **限制字符串长度**:添加约束 `CHECK(LENGTH(your_column) <= 100)` ### 方法比较 | 方法 | 优点 | 缺点 | 适用场景 | |------------|---------------------------|---------------------------|------------------------| | LENGTH比较 | 单次查询完成,效率较高 | 需要处理字符串拆分逻辑 | 中等长度字符串 | | 自定义函数 | 可复用,逻辑清晰 | 需要创建函数权限 | 高频重复使用场景 | | FIND_IN_SET| 简单直观 | 仅适用于逗号分隔值 | CSV格式数据 | ### 相关问题 1. 如何在 MySQL 中高效拆分字符串统计字符出现频率?[^1][^2] 2. 对于超长字符串(>1000字符),如何优化重复字符检测的性能?[^1] 3. MySQL 自定义函数中如何实现字符大小写不敏感的重复检测?[^2] 4. 如何利用正则表达式在 MySQL 中检测重复字符模式?[^2] 5. 在数据库设计阶段,如何避免存储包含重复字符字符串?[^3] > 提示:对于超大规模数据(百万级),建议在应用层处理字符串检测,或使用 Elasticsearch 等专业文本处理工具。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值