- 一 实现memcpy函数
- 二 大数相乘问题
- 三全排列函数的实现
- 四编写atoiitoa函数
- 五 要求编写一个函数来打乱一个字符串的顺序
- 六 求逆序对
- 七 满二叉排序树求三个结点的最小公共父节点
- 八 实现strstr函数
- 九 智力题毒酒问题
- 十 如何实现LRU算法
- 十一设计一个数据结构实现三个函数void setValueint index int value int getValueint index void setallint value使这些函数的时间复杂度为o1
- 十二 判断一个年份是否为闰年
- 十三 已知三角形三边求面积海伦公式
- 十四 计算两个日期之间的天数
- 十五 回文序列
- 十六 树的层次遍历
- 十七 字母转换为数字的问题
- 十八 写代码求二叉树中两个结点的最低公共祖先结点
- 十九 幸运袋子
- 二十 求出所有aiajn的下标i和j
- 二十一 求一个集合的所有可能子集
- 二十二 2 Keys Keyboard
- 二十三 Fraction to Recurring Decimal
一、 实现memcpy函数
题目解读:
该函数是一个内存拷贝函数
原型: void* memcpy(void* dest, const void* src, unsigned int count)
功能:由src所指内存区域赋值count个字节到dest所指向内存区域
说明:src和dest所指内存区域不能重叠,函数返回指向dest的指针
注意内存重叠的情况
代码实现:
void *Memcpy(void* dst, const void* src, int size){
char *psrc;
char *pdst;
if(NULL == dst || NULL == src){
return NULL;
}
//说明两部分内存有重复
if((src < dst) && (char *)src+size>(char *)dst){
//从后向前拷贝
psrc = (char *)src + size - 1;
pdst = (char *)dst + size - 1;
while(size--){
*pdst-- = *psrc--;
}
}else{
psrc = (char *)src;
pdst = (char *)dst;
while(size--){
*pdst++ = *psrc++;
}
}
return dst;
}
二、 大数相乘问题
题目描述:输入两个整数,要求输出这两个数的乘积。输入的数字可能超过计算机内整形数据的存储范围。
分析:由于数字无法用一个整形变量存储,很自然的想到用字符串来表示一串数字。然后按照乘法的运算规则,用一个乘数的每一位乘以另一个乘数,然后将所有中间结果按正确位置相加得到最终结果。可以分析得出如果乘数为A和B,A的位数为m,B的位数为n,则乘积结果为m+n-1位(最高位无进位时)或m+n位(最高位有进位)。因此可以分配一个m+n的辅存来存储最终结果。为了节约空间,所有的中间结果直接在m+n的辅存上进行累加。最后为了更符合我们的乘法运算逻辑,可以将数字逆序存储,这样数字的低位就在数组的低下标位置,进行累加时确定下标位置较容易些。
代码如下:
#include<iostream>
using namespace std;
//对数组逆序的函数
void reverseOrder(char *str, int p, int q) {
char temp;
while (p < q) {
temp = str[p];
str[p] = str[q];
str[q] = temp;
p++;
q--;
}
}
//完成大数相乘的函数
char *multiLargeNum(char *A, char *B) {
int m = strlen(A);
int n = strlen(B);
char *result = new char[m + n + 1];
memset(result, '0', m + n);
result[m + n] = '\0';
reverseOrder(A, 0, m - 1);
reverseOrder(B, 0, n - 1);
int multiFlag; //乘积进位
int addFlag; //加法进位
for (int i = 0; i <= n - 1; i++) {
//B的每一位
multiFlag = 0;
addFlag = 0;
for (int j = 0; j <= m - 1; j++) {
//A的每一位
int temp1 = (A[j] - '0') * (B[i] - '0') + multiFlag;
multiFlag = temp1 / 10;
temp1 = temp1 % 10;
int temp2 = (result[i + j] - '0') + temp1 + addFlag;
addFlag = temp2 / 10;
result[i + j] = temp2 % 10 + '0';
}
result[i + m] += multiFlag + addFlag;
}
reverseOrder(result, 0, m + n - 1); //再逆序回来
return result;
}
int main() {
char A[] = "3445";
char B[] = "93";
char *res = multiLargeNum(A, B);
if (res[0] != 48) {
printf("%c", res[0]);
}
printf("%s", res + 1);
delete[]res;
return 0;
}
时间复杂度分析:
3个逆序操作的时间分别为o(n)、o(m)、o(m+n),双重循环的时间复杂度为o(mn),则总的时间复杂度为o(mn+(m+n)),通常m+n<< mn,因此可近似认为为o(mn)。而且,逆序操作知识为了思考更容易,完全可以去掉。
空间复杂度为o(m+n)。
三、全排列函数的实现
例如123的全排列有123,132,213,231,312,321
代码实现如下:
#include<iostream>
using namespace std;
void swap(int &a, int &b){
int tmp = a;
a = b;
b = tmp;
}
void perm(int list[], int left, int right){
if(left == right){
for(int i=0;i<=left;i++){
cout<<list[i];
}
cout<<endl;
}else{
for(int i=left;i<=right;i++){
swap(list[i], list[left]);
perm(list, left+1, right);
swap(list[i], list[left]);
}
}
}
int main(){
int list[] = {
1, 2, 3};
perm(list, 0, 2);
return 0;
}
四、编写atoi、itoa函数
(1)整型转字符串
可以使用sprintf函数
char s[40]
Int I = 100;
sprintf(s, “%d”, i);
(2)字符串转整型
enum Status {kValid = 0, kInvalid};
int g_nStatus = kValid;
long long StrToIntCore(const char* digit, bool minus){
long long num = 0;
while(*digit != '\0'){
if(*digit >= '0' && *digit <= '9'){
int flag = minus?-1:1;
num = num * 10 + flag * (*digit - '0');
if((!minus && num > 0x7FFFFFFF) || (minus && num < (signed int)0x80000000)){
num = 0;
break;
}
digit++;
}else{
num = 0;
break;
}
}
if(*digit == '\0'){
g_nStatus = kValid;
}
return num;
}
int StrToInt(const char* str){
g_nStatus = kInvalid;
long long num = 0;
if(str != NULL && *str != '\0'){
bool minus = false;
if(*str == '+'){
str++;
}else if(*str == '-'){
str++;
minus = true;
}
if(*str != '\0'){
num = StrToIntCore(str, minus);
}
}
return (int)num;
}
五、 要求编写一个函数来打乱一个字符串的顺序
考察洗牌算法,c++的STL中有一个函数random_shuffle可以实现
vector<int> vs;
vs.push_back(0);
vs.push_back(1);
vs.push_back(2);
vs.push_back(3);
random_shuffle(vs.begin(), vs.end());
for(int i=0;i<vs.size();i++){
co