师兄面试总结编程部分解答之一

首先感谢朱宏师兄给出的总结,是一些典型的内容。

最近将编程部分看了一遍,并给出了解答,整体内容可能会比较长,可能会分为两到三篇文章里介绍。

一、字符串
1、逆序(百度面试题,要求最小的时间复杂度,个人觉得应该是方法1了)
(1) 双指针头尾互换
(2) 递归互换
(3) STL入栈出栈

void reverse(char *str)
{
	int len = strlen(str);
	//双指针头尾互换
	char tmp;
	int start = 0;
	int end = len - 1;
	while(start < end)
	{
		tmp = *(str + start);
		*(str + start) = *(str + end);
		*(str + end) = tmp;
		start++;
		end--;
	}
}

2、回文
(1)一个字符串,补充后面的字符组成回文字符串

//对原始字符串继续补充成回文
char *palindromes(char* str)
{
	int len = strlen(str);
	char* str2 = new char[len*2];//创建新的数组,用来对元素进行存放
	for(int i = 0; i < len; i++)
	{
		*(str2 + i) = *(str + i);
	}
	for(int i = 0; i < len; i++)
	{
		*(str2 + len + i) = *(str + (len - 1 - i));
	}
	*(str2 + 2*len) = '\0';
	return str2;
}

(2)在一个字符串中,找出最长的回文字符串

//找出一个字符串中最长的回文串,符合回文特征的字符子串
//aba & abba均为回文串,这个要首先明确的的一点
void findLongest(char* str)
{
	//给出的思路1,是在字符之间插入'#'以统一奇数串和偶数串,均为奇数串
	//利用现有最长子串为依据,由回文串的对称性,可以减少不必要的计算,
	//具体分析,对称点的最长子串已知,则当前最长子串的最小长度也就可以确定,对称性
	int len = strlen(str);
	const int lenNew = 2 * len + 1;
	char* str2 = new char[lenNew];
	int* p = new int[lenNew];
	int max = 0;
	int id = 0;
	for(int i = 0; i < len; ++i)
	{
		*(str2 + 2 * i) = '#';
		*(str2 + 2 * i + 1) = *(str + i);
	}
	*(str2 + 2 * len) = '#';
	//完成插入操作

	//进行统计过程
	//p[i] 存储以i位置为中心的最长回文子串长度
	//max存储当前最优结果,id存储单签最优结果对应的下标
	for(int i = 1; i < lenNew; ++i)
	{
		if (max > i)
			p[i] = p[2 * id - i] > max - i ? max - i: p[2 * id - i];//由于关于id对称,已判断的回文部分不需要再次判断,
		else
			p[i] = 1;

		for(;str2[i - p[i]] == str2[i + p[i]]; p[i]++)
			;
		p[i]--;

		if(p[i] > max)
		{
			max = p[i];
			id = i;
		}
	}
	printf("the longest one is %d \n",max);
}

(3)一个字符串中,最多有一个字符出现了奇数次,别的字符都出现了偶数次,要求将这个字符串变成回文字符串(要求最少的交换次数,不能开辟新的存储空间)(百度面试题)

//将原有字符串转换成回文串
//给出的测试字符串最多有一个出现奇数次,其他均出现偶数次,在不开辟新的存储空间的前提下,如何实现
//且交换次数尽可能少
void producePralindroms(char* str)
{
	//连续交换,从前向后遍历,并与前面的内容进行比较,如果存在相同则交换到与之对称位置处
	//交换的前提条件是对应位置的元素不同,否则,保持原位置继续向后遍历,直至结束
	//缺陷,不能够将唯一的奇数元素放到中间位置
	//改进,依然是从前向后遍历,在遍历位置,向后遍历到对称位置处,期间存在相同元素,则置换到对称位置,同时跳出内层遍历
	//不存在相同元素,则将该元素置换到中间位置,并进行下一轮遍历(新一轮遍历起始位置不变)
	int len = strlen(str);
	for(int i = 0; i < (len / 2); i++)
	{
		char cur = *(str + i);
		bool change = false;
		for(int j = i + 1; j < len - i; j++)
		{
			if(*(str + j) == cur )
			{
				//交换
				if(j != len - i - 1)
				{
					char tmp = *(str + j);
					*(str + j) = *(str + len - i - 1);
					*(str + len - i - 1) = tmp;
				}
				change = true;
				break;
			}
		}
		if(!change)//只有在存在奇数个数元素时,才可能出现这个情况
		{
			*(str + i) = *(str + len / 2);
			*(str + len / 2) = cur;
			--i;
		}

	}
	printf("%s\n",str);
}

3、左/右移动K位
(有时间复杂度的限制,要用三次交换法(剑指offer 221页)

//向左或向右移动k位
//利用翻手法则,三次变换即可
//对[start,end]区间进行翻转操作
void reverse(char* start, char* end)
{
	//最直接的头尾互换即可
	while(start < end)
	{
		char tmp = *start;
		*start = *end;
		*end = tmp;
		start++;
		end--;
	}
}
void shiftK(char* str,int k)
{
	int len = strlen(str);
	char* start = str;
	char* middle = str + len - k;
	char* end = str + len - 1;
	reverse(start,middle - 1);
	reverse(middle, end);
	reverse(start,end);
	printf("%s\n",str);
}

4、itoa
atoi
strcpy
strcat等源代码

char* myitoa(int num, char* str,int radix)
{
	char index[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	char* ptr = str;
	bool isNegative = false;
	if (num < 0)
	{
		num = -1 * num;
		isNegative = true;
	}
	while(num >= radix)
	{
		*ptr++ = index[num % radix];
		num = num / radix;
	}
	if(num)
	{
		*ptr++ = index[num];
	}
	if(isNegative)
	{
		*ptr++ = '-';
	}
	*ptr='\0';
	ptr--;
	//当前ptr指向内容为num的倒序存在,需要将其进行逆序
	char* start = str;
	char* end = ptr;
	while(start < end)
	{
		char tmp = *start;
		*start = *end;
		*end = tmp;
		start++;
		end--;
	}
	printf("%s\n",str);
	return str;
}
//将string转化为整型输出
int myatoi(const char* str)
{
	const char* ptr = str;
	int num = 0;
	bool isNegative = false;
	if(*ptr == '-')
	{
		ptr++;
		isNegative = true;
	}
	while(*ptr != '\0')
	{
		int tmp = *ptr++ - '0';
		num = num * 10 + tmp;
		
	}
	if(isNegative)
	{
		num = num * -1;
	}
	printf("%d\n",num);
	return num;
}
char* myStrcpy(char* dest, char* src)
{
	if(NULL == dest || NULL == src)
		return NULL;
	
	char* ret = dest;
	while((*dest++ = *src++) != '\0')
		;
	return ret;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值