每日一题--移除字符串中重复的字符(Cracking the Coding Interview)

题目

  • 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)移除,在前天的题目中我们已经做过找重复字符。在此题中,明确给出要求不允许额外再开一个数组,此时要向面试官问清楚, 这里是指不允许再开任何一个数组,还是说可以开一个固定大小(与字符串长度无关)的数组。
  • 如果不允许再开任何一个数组,只能用额外的一到两个变量,可以依次访问 这个数组中的字符,每访问一个,就将从该字符到结尾的所有字符中与该字符相同的元素去掉。不过这样做比较慢,时间复杂度为O(n^2 ),代码见removeDuplicate1()。
  • 如果可以开一个固定大小(与字符串长度无关)的数组,那么我们便可以用到前天找重复字符的方法,这里仅使用其中位运算的方法,代码见removeDuplicate2(),时间复杂度为O(n)。

代码

#include<iostream> 
#include<cstring>
using namespace std;

void removeDuplicate1(string &s) {
	int n = s.length();
	if(n < 2) return;
	
	int p = 0;
	for (int i = 0; i < n; i++) {	
		if(s[i] != '\0') {
			s[p++] = s[i];
			for (int j = i+1; j < n; j++) {
				if(s[i] == s[j]) s[j] = '\0';
			}
		}	
	}
	s = s.substr(0,p);
	//s[p] = '\0';
}

void removeDuplicate2(string &s) {
	int n = s.length();
	if(n < 2) return;
	
	int a[8];
	int p = 0;
	memset(a, 0, sizeof(a));
	for (int i = 0; i < n; i++) {
		int d = (int)s[i]; 
		int index = d / 32;
		int shift = d % 32;
		if(!(a[index] & 1 << shift)) {
			a[index] |= 1 << shift;
			s[p++] = s[i];
		}
	}
	s = s.substr(0,p);
}

int main() {
	string s1 = "abccdcdcde";
    string s2 = "abcdefabfgkad";
    string s3 = "";
    string s4 = "aaaaaaaa";
    string s5 = "abababababaABAB";
	string s6 = " ";
	string s7 = "ccccccdddd";
    removeDuplicate1(s1);
    removeDuplicate2(s2);
    removeDuplicate2(s3);
    removeDuplicate2(s4);
    removeDuplicate2(s5);
    removeDuplicate1(s6);
    removeDuplicate1(s7);
    cout<<s1<<endl<<s2<<endl<<s3<<endl<<s4<<endl<<s5<<endl<<s6<<endl<<s7<<endl;
    return 0;
}

程序员面试金典.Cracking the Coding Interview.第5版 英文版 一书在手,面试机会我有 这本书详细讲解了一般技术公司面试的流程,评价标准设置,最后还有一个章节为你在薪水上讨价还价进行支招。 当然,书最核心的还是面试的题目了。本书的题目以算法和数据结构为主,但也分别有一个章节涵盖分布式系统设计,c/c++、java、sql、多线程等知识性的内容。所有题目都有解答思路和答案,算法题目的实现使用了java。只要有一点java基础的同学,应该都可以看明白。 书有一道习题使用了后缀树。后缀树这个特殊的结构在《算法导论》等众多书都没有出现,可以在网上找到一些计算生物学的课件。很多匹配字符串相关的问题都可以用后缀树或者广义后缀树给出一个线性解法。但注意的是这个数据结构所占用的空间也是很大的。虽然一些情况下可以优化到线性,但这种优化在一些具体的问题会改变问题的语意,因此不是任何时候都可以适用的。对后缀树和广义后缀树感兴趣可以参考http://book.douban.com/subject/1765938/,网上也可以找到一些相关的课件 书有”连续子序列最大和值“和”最长递增子序列“这样的题目。但是没有包含”连续子序列最大积值“这样的题目,并且”最长递增子序列“给出的解答不是最优的,这两个题目大家可以额外思考一下,面试也很常见。 另外,面试过程也会遇到很多与系统相关的知识性的题目,如流水线、虚拟内存、进程线程、地址空间结构、异常处理、并发编程等等,这些内容可以参考《深入理解计算机系统》http://book.douban.com/subject/5407246/。 网络相关的内容可以参考《TCP/IP详解》卷一http://book.douban.com/subject/1099252/。 一些更具体的内容,如linux启动过程、linux文件系统原理、浏览器访问网址过程等,可以查看wikipedia相关页面,linux相关的内容可以访问鸟哥的私房菜基础篇的相关文章http://linux.vbird.org/linux_basic/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值