经典算法面试题目-设计算法移除字符串中重复的字符(1.3)

简介: 经典算法面试题目-设计算法移除字符串中重复的字符(1.3)

题目


Design an algorithm and write code to remove the duplicate characters in a string without using any additional buffer. NOTE: One or two additional variables are fine. An extra copy of the array is not.


FOLLOW UP


Write the test cases for this method.


设计算法并写出代码移除字符串中重复的字符,不能使用额外的缓存空间。注意: 可以使用额外的一个或两个变量,但不允许额外再开一个数组拷贝。


进一步地,


为你的程序写测试用例。


解答


这道题目其实是要你就地(in place)将字符串中重复字符移除。你可以向面试官问清楚, 不能使用额外的一份数组拷贝是指根本就不允许开一个数组,还是说可以开一个固定大小, 与问题规模(即字符串长度)无关的数组。


如果根本就不允许你再开一个数组,只能用额外的一到两个变量。那么,你可以依次访问 这个数组的每个元素,每访问一个,就将该元素到字符串结尾的元素中相同的元素去掉( 比如置为’\0′).时间复杂度为O(n2 ),代码如下:

void removeDuplicate(char s[])
{
    int len = strlen(s);
    if(len < 2) return;//只有一个字符,肯定没有重复的
    int p = 0;//相当于一个游标
    //从0开始找不重复的字符
    for(int i=0; i < len; ++i)
    {
        if(s[i] != '\0')
        {
            s[p++] = s[i];
            for(int j=i+1; j < len; ++j)
                if(s[j]==s[i])
                    s[j] = '\0';
        }
    }
    s[p] = '\0';
}


如果可以开一个固定大小,与问题规模(即字符串长度)无关的数组,那么可以用一个数组来 表征每个字符的出现(假设是ASCII字符,则数组大小为256),这样的话只需要遍历一遍字符 串即可,时间复杂度O(n)。代码如下:


void removeDuplicate(char s[])
{
    int len = strlen(s);
    if(len < 2) return;
    bool c[256];//这个用true来标识这个字符出现过了。相比上个节省了时间。
    memset(c, 0, sizeof(c));
    int p = 0;
    for(int i=0; i < len; ++i)
    {
        if(!c[s[i]])
        {
            s[p++] = s[i];
            c[s[i]] = true;
        }
    }
    s[p] = '\0';    
}


如果字符集更小一些,比如只是a-z,即字符串里只包含小写字母,那么使用一个int变量中 的每一位来表征每个字符的出现,一样可以在O(n)的时间里移除重复字符,而且还不需要额 外开一个数组。代码如下:


void removeDuplicate(char s[])
{
    int len = strlen(s);
    if(len < 2) return;
    int check = 0, p = 0;
    for(int i=0; i < len; ++i)
    {    
        //int变量本身在内存中占4字节也就是32位!!
        int v = (int)(s[i]-'a');
        //如果没有出现重复的字母(字母种数小于32种),就不会出现(check & (1 << v)==1的情况!
        if((check & (1 << v))==0)
        {
            s[p++] = s[i];
            check |= (1 << v);
        }
    }
    s[p] = '\0';
}


测试用例:

不包含重复字符的字符串,比如:abcd

字符串全是重复字符,比如:aaaa

空字符串

重复字符连续出现,比如:aaabbb

重复字符不连续出现,比如:abababa

完整代码如下:

#include <iostream>
#include <cstring>
using namespace std;
string removeDuplicate1(string s)
{
    int check = 0;
    int len = s.length();
    if(len < 2) return s;
    string str = "";
    for(int i=0; i<len; ++i)
    {
        int v = (int)(s[i]-'a');
        if((check & (1<<v)) == 0)
        {
            str += s[i];
            check |= (1<<v);
        }
    }
    return str;
}
string removeDuplicate2(string s)
{
    int len = s.length();
    if(len < 2) return s;
    string str = "";
    for(int i=0; i<len; ++i)
    {
        if(s[i] != '\0')
        {
            str += s[i];
            for(int j=i+1; j<len; ++j)
                if(s[j]==s[i])
                    s[j] = '\0';
        }
    }
    return str;
}
void removeDuplicate3(char s[])
{
    int len = strlen(s);
    if(len < 2) return;
    int p = 0;
    for(int i=0; i<len; ++i)
    {
        if(s[i] != '\0')
        {
            s[p++] = s[i];
            for(int j=i+1; j<len; ++j)
                if(s[j]==s[i])
                    s[j] = '\0';
        }
    }
    s[p] = '\0';
}
void removeDuplicate4(char s[])
{
    int len = strlen(s);
    if(len < 2) return;
    bool c[256];
    memset(c, 0, sizeof(c));
    int p = 0;
    for(int i=0; i<len; ++i)
    {
        if(!c[s[i]])
        {
            s[p++] = s[i];
            c[s[i]] = true;
        }
    }
    s[p] = '\0';    
}
void removeDuplicate5(char s[])
{
    int len = strlen(s);
    if(len < 2) return;
    int check = 0, p = 0;
    for(int i=0; i<len; ++i)
    {
        int v = (int)(s[i]-'a');
        if((check & (1<<v))==0)
        {
            s[p++] = s[i];
            check |= (1<<v);
        }
    }
    s[p] = '\0';
}
int main()
{
    string s1 = "abcde";
    string s2 = "aaabbb";
    string s3 = "";
    string s4 = "abababc";
    string s5 = "ccccc";
    cout<<removeDuplicate1(s1)<<" "<<removeDuplicate2(s1)<<endl;
    cout<<removeDuplicate1(s2)<<" "<<removeDuplicate2(s2)<<endl;
    cout<<removeDuplicate1(s3)<<" "<<removeDuplicate2(s3)<<endl;
    cout<<removeDuplicate1(s4)<<" "<<removeDuplicate2(s4)<<endl;
    cout<<removeDuplicate1(s5)<<" "<<removeDuplicate2(s5)<<endl;
    char ss1[] = "abcde";
    char ss2[] = "aaabbb";
    char ss3[] = "";
    char ss4[] = "abababc";
    char ss5[] = "ccccc";
    removeDuplicate5(ss1);
    removeDuplicate5(ss2);
    removeDuplicate5(ss3);
    removeDuplicate5(ss4);
    removeDuplicate5(ss5);
    cout<<ss1<<" "<<ss2<<" "<<ss3<<" "<<ss4<<" "<<ss5<<endl;
    return 0;
}


测试结果如下:

image.png

目录
相关文章
|
2月前
|
算法
【算法】位运算算法——判断字符是否唯一
【算法】位运算算法——判断字符是否唯一
|
2月前
|
算法
【算法】滑动窗口——无重复字符的最长子串
【算法】滑动窗口——无重复字符的最长子串
|
2天前
|
缓存 关系型数据库 MySQL
面试题目总结
面试题目总结
22 6
|
2月前
|
安全 Java 编译器
【Java基础面试二十九】、说一说你对字符串拼接的理解
这篇文章讨论了Java中字符串拼接的四种常用方式(使用`+`运算符、`StringBuilder`、`StringBuffer`和`String`类的`concat`方法),每种方式适用的场景,以及在不同情况下的性能考量。
|
2月前
|
Java
【Java基础面试二十八】、使用字符串时,new和““推荐使用哪种方式?
这篇文章讨论了在Java中使用字符串时,推荐使用双引号`""`直接量方式而不是使用`new`操作符,因为`new`会在常量池之外额外创建一个对象,导致更多的内存占用。
|
2月前
|
算法 Java
LeetCode经典算法题:矩阵中省份数量经典题目+三角形最大周长java多种解法详解
LeetCode经典算法题:矩阵中省份数量经典题目+三角形最大周长java多种解法详解
39 6
|
4月前
|
缓存 Java 数据库连接
java面试题目 强引用、软引用、弱引用、幻象引用有什么区别?具体使用场景是什么?
【6月更文挑战第28天】在 Java 中,理解和正确使用各种引用类型(强引用、软引用、弱引用、幻象引用)对有效的内存管理和垃圾回收至关重要。下面我们详细解读这些引用类型的区别及其具体使用场景。
49 3
|
3月前
|
存储 安全 Java
Java面试题:请解释Java中的字符串和字符串缓冲区?
Java面试题:请解释Java中的字符串和字符串缓冲区?
26 0
|
3月前
|
存储 算法
经典的滑动窗口的题目 力扣 2799. 统计完全子数组的数目(面试题)
经典的滑动窗口的题目 力扣 2799. 统计完全子数组的数目(面试题)
|
4月前
|
算法
【经典LeetCode算法题目专栏分类】【第10期】排序问题、股票问题与TOP K问题:翻转对、买卖股票最佳时机、数组中第K个最大/最小元素
【经典LeetCode算法题目专栏分类】【第10期】排序问题、股票问题与TOP K问题:翻转对、买卖股票最佳时机、数组中第K个最大/最小元素
下一篇
无影云桌面