马上要面试搜狗的windows开发了,准备花两天时间复习一下windows开发和基本算法。
主要读 多线程编程系列 ,July的算法面试 。看了这篇攻略 决定老老实实的去刷完100题,打持久战。但面试迫在眉睫,按照July说的那样刷上3年,黄花菜都凉了。我得急功近利一点,针对性的准备。今天下午先搞定String类的面试题,包括String类算法题和经典函数的实现。
2014-9-6
1.字符串类题目
1.1字符串旋转
字符串左旋:
/*
题目:1.1 旋转字符串
题目描述:
给定一个字符串,要求把字符串前面的若干个字符移动到字符串的尾部,
如把字符串“abcdef”前面的2个字符'a'和'b'移动到字符串的尾部,使
得原字符串变成字符串“cdefab”。请写一个函数完成此功能,要求对长
度为n的字符串操作的时间复杂度为 O(n),空间复杂度为 O(1)。
思路:abcdef -> bafedc -> cdefab(考研原题)
*/
#include <iostream>
#include <cstring>
//在长度为n的字符串中反转前a个字母
void ReverseString(char *str, int a, int b) {
int i = a, j = b - 1;
while (i < j) {
char tmp = str[i];
str[i] = str[j];
str[j] = tmp;
++i;
--j;
}
}
int main() {
char s[] = "abcdef";
int a = 2;
int n = strlen(s);
printf("初始字符串: %s\n", s);
ReverseString(s, 0, a);
ReverseString(s, a, n);
ReverseString(s, 0, n);
printf("转换后的字符串: %s\n", s);
system("pause");
return 0;
}
链表左旋:
/*
题目:
链表翻转。给出一个链表和一个数k,比如,
链表为1→2→3→4→5→6,k=2,则翻转后2→1→6→5→4→3,
若k=3,翻转后3→2→1→6→5→4,若k=4,翻转后4→3→2→1→6→5,
用程序实现。
思路:
*/
#include <iostream>
struct LinkList {
int val;
LinkList *next;
LinkList(int v): val(v), next(NULL) {
}
};
//反转单向链表:第s个和第e个结点(s, s + 1, ..., e - 1)
LinkList* ReviseLinkList(LinkList *h, int s, int e) {
int i = 0;
//找到链表的头部
LinkList *c = h;
while (i < s) { //去掉头结点
c = c->next;
++i;
}
//开始反转 c-> linklist...
if (c != NULL) {
LinkList *p = c->next;
if (p != NULL) {
LinkList *q = p->next;
LinkList *start = p;
start->next = NULL;
if (q != NULL) {
LinkList *k = q->next;
// p -> q -> k,去掉首尾
while (i < e - 2 && k != NULL) {
q->next = p;
p = q;
q = k;
k = k->next;
++i;
}
if (k != NULL) {
start->next = k;
}
}
q->next = p;
c->next = q;
}
}
return h;
}
void printLinkList(LinkList *l) {
while (l != NULL) {
printf("%d->", l->val);
l = l->next;
}
printf("END\n");
}
int main() {
//带表头的单链表
LinkList *head = new LinkList(0);
LinkList *node1 = new LinkList(1);
head->next = node1;
LinkList *node2 = new LinkList(2);
node1->next = node2;
LinkList *node3 = new LinkList(3);
node2->next = node3;
LinkList *node4 = new LinkList(4);
node3->next = node4;
LinkList *node5 = new LinkList(5);
node4->next = node5;
LinkList *node6 = new LinkList(6);
node5->next = node6;
printf("初始链表:");
//0->1->2->3->4->5->6
printLinkList(head);
head = ReviseLinkList(head, 0, 2);
//0->2->1->3->4->5->6
printLinkList(head);
head = ReviseLinkList(head, 2, 7);
printf("旋转后的链表:");
//0->2->1->6->5->4->3
printLinkList(head);
system("pause");
return 0;
}
翻转单词
/*
题目:
单词翻转。输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺
序不变,句子中单词以空格符隔开。为简单起见,标点符号和普通字母一样
处理。例如,输入“I am a student.”,则输出“student. a am I”。
思路:
*/
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
int main() {
string str = "I am a student.";
istringstream is(str);
vector<string> a;
while (is >> str) {
a.push_back(str);
}
string out = "";
for (int i = a.size() - 1; i > 0; --i) {
out += a[i];
out += " ";
}
out += a[0];
cout << out << endl;
system("pause");
return 0;
}
1.2 字符串包含
/*
题目:
给定两个分别由字母组成的字符串A和字符串B,字符串B的长度比字符串A短。请问,如何最快
地判断字符串B中所有字母是否都在字符串A里?
思路:
1.判断string2中的字符是否在string1中?最直观也是最简单的思路是,
针对string2中每一个字符,逐个与string1中每个字符比较,看它是否在
String1中。
bool CheckContain(string &s1, string &s2) {
bool ret = true;
for (int i = 0; i < s2.size(); ++i) {
bool contain = false;
for (int j = 0; j < s1.size(); ++j) {
if (s2[i] == s1[j])
contain = true;
}
ret &= contain;
}
return ret;
}
2.如果允许排序的话,我们可以考虑下排序。比如可先对这两个字符串的字
母进行排序,然后再同时对两个字串依次轮询。两个字串的排序需要(常规情
况)O(m log m) + O(n log n)次操作,之后的线性扫描需要O(m+n)次操作。
bool CheckContain(string &s1, string &s2) {
sort(s1.begin(), s1.end());
sort(s2.begin(), s2.end());
for (int i = 0, j = 0; j < s2.size(); ++j) {
while (i < s1.size() && s1[i] < s2[j]) {
++i;
}
if (i >= s1.size() || s1[i] > s2[j]) {
return false;
}
}
return true;
}
3.hash法:
'A'65, 'a' 97
用64位longlong表示
*/
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
void printHash(unsigned long long h) {
for (int i = 63; i >= 0; --i) {
long long t = 1;
if ((h & (t << i)) != 0) {
cout << "1";
} else {
cout << "0";
}
}
cout << endl;
}
bool CheckContain(string &s1, string &s2) {
long long hash = 0;
long long t = 1;
for (int i = 0; i < s1.size(); ++i) {
hash |= (long long)(t << (s1[i] - 'A'));
}
printHash(hash);
printHash(1 <<('S' - 'A'));
for (int i = 0; i < s2.size(); ++i) {
if ((hash & (t << (s2[i] - 'A'))) == 0)
return false;
}
return true;
}
int main() {
string str1 = "BCDEFGPOAas";
string str2 = "BAADEa";
string str3 = "AS";
cout << str1 + " " + str2 + " 比较结果: " <<
CheckContain(str1, str2) << endl;
cout << str1 + " " + str3 + " 比较结果: " <<
CheckContain(str1, str3) << endl;
system("pause");
return 0;
}
第三种方法调试了好久才意识到 1 << a, 如果a > 31会溢出,所以这里的1应有int类型换成long long。