常见面试题

/*======================================================================
    
======================================================================*/
//链家笔试:
//实现两个大整数相乘
//方法一:首先,我们用两个字符串来保存我们的大整数,num1[100], num2[100]
//        然后,求num2的每一位与num1的乘积,保存到tempRes中。
//        过程为:res保存每位相乘的结果,carry用来保存进位,每位相乘之后还要加上进位才是真的结果。
//        将res的个位保存到tempRes中,其他位则为下一位相乘的进位。
//          再然后,将tempRes与result求和,每求一次,向左偏移一位。
//          res为每位之和再加上进位,这里很重要,然后保存到result里只是res的个位,res为下一位计算的进位。
#include<stdio.h>
#include<string.h>
#include<malloc.h>

#define and &&
#define or ||
#define not !
#define Int(X) (X - '0')
#define Char(X) (X + '0')

char *multiBigInteger(const char *, const char *);
int checkNum(const char *);

int main(void)
{
    char num1[100] = {'\0'}, num2[100] = {'\0'};
    while(scanf("%s%s", num1, num2) != EOF)
    {
        char *result = "0";
        if(strlen(num1) > 100 or strlen(num2) > 100)
        {
            printf("ERROR\n");
            return 1;
        }
        if(checkNum(num1) or checkNum(num2))
        {
            printf("ERROR: input must be an Integer\n");
            return 1;
        }
        printf("num1:\t%s\nnum2:\t%s\n", num1, num2);
        result = multiBigInteger(num1, num2);
        if(result[0] == '0')
        {
            int i;
            printf("result:\t");
            for(i = 1; (size_t)i < strlen(result); i++)
            {
                printf("%c", result[i]);
            }
            printf("\n");
        }
        else
        {
            printf("result:\t%s\n", result);
        }
        printf("\n");
    }
    return 0;

int checkNum(const char *num)
{
    int i;
    for(i = 0; (size_t)i < strlen(num); i++)
    {
        if(num[i] < '0' or num[i] > '9')
        {
            return 1;
        }
    }
    return 0;
}

char *multiBigInteger(const char *num1, const char *num2)
{
    char *tempRes = NULL;              //用来保存每次相乘的结果
    char *result = NULL;               //用来保存最终结果
    int tempResLen;                    //每次相乘结果的最大长度
    int num1Len = strlen(num1);        //num1的长度
    int num2Len = strlen(num2);        //num2的长度
    int resultLen;                     //结果的最大长度
    int i, j, k;                       //循环计数器
    int res;                           //每次一位相乘/相加的结果
    int carry = 0;                     //进位
    int offset = 0;                    //加法的偏移位
    resultLen = num1Len + num2Len - 1; //结果长度最大为num1长度和num2长度之和,由于下标从0开始,所以要减一
    tempResLen = num1Len;              //每次num1乘以num2每一位的结果最大长度是num1Len+1,由于下标从0开始,所以减一后约去1,只剩num1Len
    //初始化result为0
    result = (char *)malloc((resultLen+2)*sizeof(char));
    memset(result, '0', (resultLen+1)*sizeof(char));
    result[resultLen+1] = 0;

    tempRes = (char *)malloc((tempResLen+2)*sizeof(char));
    for(j = num2Len - 1; j >= 0; j--)
    {
        //初始化tempRes每位为0
        memset(tempRes, '0', (tempResLen+1)*sizeof(char));
        /*计算num1与num2各位相乘的结果,保存到tempRes中
         *每一位相乘后与之前的进位相加得出res,将res的个
         *位(res%10)保存到tempRes里,然后将res的其余位数
         *(res/10)则为进位carry*/
        for(i = num1Len-1; i >= 0; i--)
        {
            res = Int(num1[i]) * Int(num2[j]) + carry;
            tempRes[tempResLen--] = Char(res % 10);
            carry = res / 10;
        }
        //tempRes第一位为进位,刚刚的循环是没有算的,最后把进位算上
        tempRes[tempResLen] = Char(carry);
        tempResLen = num1Len;
        carry = 0;
        //由result的末尾开始计算和,算完一次,向左偏移一位
        for(k = resultLen-offset; k > (resultLen-offset-num1Len); k--)
        {
            res = Int(result[k]) + Int(tempRes[tempResLen--]) + carry;
            result[k] = Char(res%10);
            carry = res/10;
        }
        result[k] += Int(tempRes[tempResLen] + carry);
        carry = 0;
        tempResLen = num1Len;
        offset++;

    }
    printf("num1Len:%d\nnum2Len:%d\n", num1Len, num2Len);
    return result;
}
方法二:
#include<stdio.h>
#include<string.h>
#include<malloc.h>

#define and &&           /**************/
#define or ||            /* python风格 */
#define not !            /*            */
#define Int(X) (X - '0') /**************/

int *multiBigInteger(const char *, const char *);
int checkNum(const char *);

int main(void)
{
    char num1[100] = {'\0'}, num2[100] = {'\0'};
    printf("Please input two nunber(less than 100 digits):\n> ");
    while(scanf("%s%s", num1, num2) != EOF)
    {
        int *result = NULL;
        int i, change = 0;
        //对输入的数据进行检验
        if(strlen(num1) > 100 or strlen(num2) > 100)
        {
            printf("per number must less than 100 digits\n");
            return 1;
        }

        if(checkNum(num1) or checkNum(num2))
        {
            printf("ERROR: input must be an Integer\n");
            return 1;
        }

        printf("num1:\t%s\nnum2:\t%s\n", num1, num2);

        result = multiBigInteger(num1, num2);

        /* 输出结果result,result[0]保存着result的长度,
         * 所以下标要从1开始 */
        printf("result:\t");
        for(i = 1; i <= result[0]; i++)
        {
            if(result[i] != 0) //这一步用来去掉前导0,第一位为0跳过不输出
                change = 1;
            if(not change)
            {
                if(i > 1)        //这一步用来判断结果是否为0,
                    {                //如果结果第二位还是0,就判断为0
                        printf("0");
                        break;
                    }
                continue;
            }
            printf("%d", result[i]);
        }
        printf("\n");
        printf("\nPlease input two nunber(less than 100 digits):\n> ");
    }
    return 0;

//用于检测输入的是否是数字,如果是就返回0,不是就返回1
int checkNum(const char *num)
{
    int i;
    for(i = 0; (size_t)i < strlen(num); i++)
    {
        if(num[i] < '0' or num[i] > '9')
        {
            return 1;
        }
    }
    return 0;
}

//返回结果result,为一片内存块,类似数组
int *multiBigInteger(const char *num1, const char *num2)
{
    int *result = NULL;                //用来保存最终结果
    int num1Len = strlen(num1);        //num1的长度
    int num2Len = strlen(num2);        //num2的长度
    int resultLen;                     //结果的最大长度
    int i, j;                          //循环计数器
    resultLen = num1Len + num2Len;     //结果长度最大为num1长度和num2长度之和
    //初始化result为0
    result = (int *)malloc((resultLen+1)*sizeof(int));
    memset(result, 0, (resultLen+1)*sizeof(int));

    result[0] = resultLen; //result的第一位是用来保存result的长度的。
    /* num1乘以num2,由于这里采用先不进位的算法,所以算法是按从左到右
     * 按顺序来乘,然后将每位的结果保存到result的每一位中,循环一次
     * reult就从下一位开始求和。如下:(左边为正常算法,右边为本程序算法)
     *
     *     54321     |     54321
     *    ×  123     |    ×  123
     *    -------    |   --------
     *    162963     |     54321
     *   108642      |     108642
     *   54321       |      162963
     *   --------    |   ---------
     *   6681483     |     6681483
     *
     * */
    for(j = 0; j < num2Len; j++)
    {
        for(i = 0; i < num1Len; i++)
        {
            /* result第一位是用来保存result长度的,而第二位是保存结果最后的进位的
             * 没有进位,则result[1]为0,所以每位相乘之和是从第三位(即result[2])
             * 开始。这里是本程序的比较巧妙的地方,需要仔细想想。
             * */
            result[i+j+2] += Int(num1[i]) * Int(num2[j]);
        }
    }

    /* 这个循环用来处理进位的,所以要从result的最后一位一直处理到首位。
     * 要注意result的总长度是resultLen+1,有一位是保存result的长度,而
     * C语言下标是从0开始,所以result的最后一位的下标就是resultLen,而
     * 第一位就是1。*/
    for(i = resultLen; i > 1; i--)
    {
        result[i-1] += result[i]/10;
        result[i] = result[i]%10;
    }
    printf("num1Len:%d\nnum2Len:%d\n", num1Len, num2Len);
    return result;
}

//1.如何判断合法的IP地址,尽可能考虑各种情况 (腾讯面试题)
static int CountPoint(const char *str)
{
    int count = 0;
    while(*str != '\0')
    {
        if(*str == '.')
            count++;
        str++;
    }
    return count;
}

//判断IPV4的地址是否合法的程序
//只对IP地址如下规则做了判断,其它的同学们可以补充
//IP地址的规则是: (1~255).(0~255).(0~255).(0~255)。例如192.168.2.1
bool IsIP(const char *str)
{
    const char *p = NULL;
    int num = 0;
    if(str == NULL)
    {
        return false;
    }
    if(CountPoint(str) != 3)//IP地址只有3个.号
    {
        return false;
    }
    if(str[0]=='0')//IP地址起始不能为0
    {
        return false;
    }
    while(*str != '\0')
    {
        if(isdigit(*str))
        {
            num = num*10 + *str - '0';
        }
        else if(*str != '.' || num>255)
        {
            return false;
        }
        else
        {
            num = 0;
        }
        str++;
    }
    if(num > 255)//处理尾部数据
        return false;

    return true;
}

int main()
{
    char *str[] = {"192.168.1.1","1.0.0","1.0.0.0","256.1.2.1","192.1.1.256"};
    for(int i=0;i<sizeof(str)/sizeof(str[0]);i++)
    {
        if(IsIP(str[i]))
        {
            printf("%s 是合法的IP\n",str[i]);
        }
        else
        {
            printf("%s 不是合法的IP\n",str[i]);
        }
    }
    return 0;
}
//第一题结束


//2.算法题:求一个有序数组中两个值相加为k的数字,返回这两个数字的下标。(腾讯面试题)
//算法分析:有序的数组(假设非降序),采取双向遍历,一个从前往后,一个从后往前,当前数字相加如果相等则返回,如果小于k则前面的继续往后,如果大于k则后面的继续往前
//代码如下:
typedef struct Pairs
{
    int x;//第一个数的下标
    int y;//第二个数的下标
}Pairs;

//求一个有序数组中两个值相加为k的数字,返回这两个数字的下标。
//找到返回正常的下标,查找失败返回-1
Pairs SumToK(int *arr,int len,int k)//时间复杂度O(n),空间复制度O(1)
{
    Pairs pa = {-1,-1};
    int low = 0;        //从前往后遍历
    int high = len-1;//从后往前遍历
    int sum;

    while(low <= high)
    {
        sum = arr[low] + arr[high];
        if(sum < k)
        {
            low++;
        }
        else if(sum > k)
        {
            high--;
        }
        else
        {
            pa.x = low;
            pa.y = high;
            break;
        }
    }
    return pa;
}

int main()
{
    int arr[] = {1,3,5,6,17,18,29,33,44,55,89};
    int k = 9;
    Pairs pa = SumToK(arr,sizeof(arr)/sizeof(arr[0]),k);
    if(pa.x == -1)
        printf("没有两数相加等于%d\n",k);
    else
        printf("相加等于%d的为%d,%d下标的值\n",k,pa.x,pa.y);

    k = 50;
    pa = SumToK(arr,sizeof(arr)/sizeof(arr[0]),k);
    if(pa.x == -1)
        printf("没有两数相加等于%d\n",k);
    else
        printf("相加等于%d的为%d,%d下标的值\n",k,pa.x,pa.y);

    k = 4;
    pa = SumToK(arr,sizeof(arr)/sizeof(arr[0]),k);
    if(pa.x == -1)
        printf("没有两数相加等于%d\n",k);
    else
        printf("相加等于%d的为%d,%d下标的值\n",k,pa.x,pa.y);

    k = 1;
    pa = SumToK(arr,sizeof(arr)/sizeof(arr[0]),k);
    if(pa.x == -1)
        printf("没有两数相加等于%d\n",k);
    else
        printf("相加等于%d的为%d,%d下标的值\n",k,pa.x,pa.y);
}
//TODO,如果相加为k的有多组,上面的算法并没有实现,例如k=50,有6+44,17+33

//2.2,如果是无序的数组呢?
//算法分析:1.如果都是非负的数字,则可以建立一个k长度的哈希表,哈希表中每个元素保存值和下标,遍历整个数组一遍把大于k的值直接丢弃(相加不可能为k)小于等于k的值保存到哈希表,然后利用上面的算法遍历哈希表即可.

//3.用c语言判断操作系统是32位的还是64位 
//分析:这个题目应该是判断当前平台是32位还是64位,最简洁的办法是判断指针的大小,如果4字节则为32位,8字节位64位,sizeof(int *);

//4.泛型冒泡(腾讯面试题)
typedef int (*PCmp)(void *vp1,void *vp2);//泛型比较

//泛型冒泡
void BubbleSort(void *arr,int len,int elemsize,PCmp cmp)
{
    void *tmp = malloc(elemsize);//交换数据的中间变量
    void *var1;//冒泡的第一个值的指针
    void *var2;//冒泡的第二个值的指针

    for(int i=0;i<len-1;i++)
    {
        for(int j=0;j+1<len-i;j++)
        {
            var1 = (char *)arr+j*elemsize;
            var2 = (char *)arr + (j+1)*elemsize;
            if(cmp(var1,var2) > 0)  //交换数据
            {
                memcpy(tmp,var1,elemsize);
                memcpy(var1,var2,elemsize);
                memcpy(var2,tmp,elemsize);
            }
        }
    }
}

int Cmp_int(void *vp1,void *vp2)
{
    return *(int *)vp1 - *(int *)vp2;
}

int Cmp_str(void *vp1,void *vp2)
{
    return strcmp(*(char **)vp1,*(char **)vp2);
}

int main()
{
    int arr[] = {3,5,7,9,0,12,45,6,78,23,44,10};
    BubbleSort(arr,sizeof(arr)/sizeof(arr[0]),sizeof(int),Cmp_int);

    char *brr[] = {"abc","aaa","bcd","xyz","ccccc","hhh"};
    BubbleSort(brr,sizeof(brr)/sizeof(brr[0]),sizeof(char *),Cmp_str);

    return 0;
}

//5.(腾讯面试题)
假设环境均为x86,32位机器,linux环境下1、以下代码执行后b的值是什么
int a = 0xabcdefff;
char b = (char)a;
b=?
解答:将宽的数据类型强转成窄类型时,保留低数据,则b的值为0xff即-1

//6.(腾讯面试题)
c语言编码,实现函数long htonl(long a),也就是将主机序转化为网络序
//解析:主机序也称为本地字节序,分为大端和小端.大端:低地址放大数据;小端:低地址放小数据.网络序统一为大端
//该算法主要需要测试主机序,如果是大端则不做任何的改变,如果是小端则逆序

bool IsLittle()//判断主机序是否为小端
{
    short a  = 0x0001;//小数据为0x01,高数据为0x00
    return *(char *)&a == 0x01; //低地址放小数据
}

long Htonl(long a)
{
    long b = 0;

    if( !IsLittle() )//大端
    {
        return a;
    }

    for(int i=0;i<sizeof(a);i++)//小端:0x12345678->0x78563412
    {                                        //处理单位为字节,1字节8位
        b = (b<<8) | (a & 0xff);
        a >>= 8;      
    }
    return b;
}

int main()
{
    printf("%x\n",Htonl(0x12345678));

    return 0;
}

//7、有一个集合由A-Z这26个字母组成,打印这个集合的所有子集,每个子集一行,写C代码实现,不能使用递归(腾讯面试题)
//解析:https://blog.csdn.net/K346K346/article/details/80436430

//str为A~Z的字母集合,n为需要处理的前n个字符集合,本题n为26,n是为了方便测试
void SubSet(int n)
{
    const char *str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    int maxnum = 1<<n;          //2^n
    for(int i=0;i<maxnum;i++)//处理0到2^n  -1之间的数字
    {
        for(int j=0;j<n;j++)//j表示二进制右数第几位
        {
            if( (i&(1<<j)) != 0)//表示当前位不为0,则需要打印相应的字母
            {
                printf("%c ",str[j]);
            }
        }
        printf("\n");
    }
}

int main()
{
    SubSet(3);
    //printf("-----------\n");
    //SubSet(26);//数据太大不好统计测试结果

    return 0;
}


//8、介于0到1000000之间的n个整数,请对他们进行排序,要求时间复杂度为O(n),写c代码实现(腾讯面试题) 
//算法解析:定义一个长度为1000000的数组brr,全部初始化为0,从头到尾遍历这n个数字,出现哪个数字则将其作为下标对应的数组值加1(哈希函数为y=x),然后从到到尾遍历brr,数字是几则将下标打印几次

void Sort(int *arr,int n) //时间复杂度O(n),空间复杂度O(数据的取值范围)
{
    int i;
    for(i=0;i<n;i++)
    {
        if(arr[i]<0 || arr[i]>=1000000)
        {
            printf("数据不在范围内,错误\n");
            return ;
        }
    }
    int *brr = (int *)calloc(1000000,sizeof(int));//calloc将每个值设为0
    assert(brr != NULL);
    for(i=0;i<n;i++)
    {
        brr[arr[i]]++;//哈希函数y = x = arr[i]
    }

    i = 0; 
    for(int j=0;j<1000000;j++)
    {
        for(int k=0;k<brr[j];k++)
        {
            arr[i++] = j;
        }
    }
    free(brr);
}

int main()
{
    int arr[] = {5,8,0,9,12,34,56,7,8,89,13,44,76,88,98,69};
    Sort(arr,sizeof(arr)/sizeof(arr[0]));

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值