[windows C/C++]面试准备(一)字符串类面试题1

马上要面试搜狗的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。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值